Systemd Units

The user, group, and service will be called foobar.

Service account

The unprivileged user will run the service.

sudo addgroup --system foobar
sudo adduser --system \
    --disabled-login \
    --ingroup foobar \
    --shell /bin/nologin \
    --no-create-home foobar

Systemd unit

The unit file should be created at /etc/systemd/system/foobar.service

[Unit]
Description=FooBar
Documentation=https://docbot.onetwoseven.one

[Service]
Type=simple
ExecStart=/opt/foobar/startup
ExecStop=/opt/foobar/stop
ExecReload=/opt/foobar/reload
PIDFile=/run/foobar.pid
WorkingDirectory=/opt/foobar/
User=foobar
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Once the unit file is created, it can be enabled and started:

sudo systemctl daemon-reload
sudo systemctl start foobar.service
sudo systemctl enable foobar.service

Environment variables

Variables can be specified in the unit file in the service section:

[Service]
...
Environment=MYVAR="myvalue"

Or, an environment file can be created

MYVAR="myvalue"

And referenced in the unit file

EnvironmentFile=/opt/foobar/vars

CGroups

You can enable cgroups for the unit to allow resource tracking and limits:

[Service]
...
Slice=foobar.slice
MemoryAccounting=yes
CPUAccounting=yes

See also: https://www.redhat.com/sysadmin/cgroups-part-four

Sandboxing

Sandboxing can be enabled by turning on these options in the [Service] section:

[Service]
...
ProtectSystem=full
ProtectHome=yes
PrivateDevices=yes
NoNewPrivileges=yes
PrivateTmp=yes

More extensive options, but more likely to cause issues.

ProtectControlGroups=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectHostname=true
KeyringMode=private
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM

Disallowing W^X frequently causes issues with Java applications.

For more info: