Systemd fails to load caddy on a raspberry Pi


(Jean-Luc Lacroix) #1

Installation went flawlessly and test runs were also successful launching the caddy binary from the command line. This became a bit more complicated when I tried to run caddy as a systemd service using the caddy.service file available on github.

The service would no launch and the logs showed:
Jan 02 15:13:17 raspberrypi systemd[1]: Started Caddy HTTP/2 web server.
Jan 02 15:13:17 raspberrypi caddy[1378]: Activating privacy features… done.
Jan 02 15:13:17 raspberrypi caddy[1378]: 2018/01/02 15:13:17 listen tcp :80: bind: permission denied
Jan 02 15:13:17 raspberrypi systemd[1]: caddy.service: Main process exited, code=exited, status=1/FAILURE
Jan 02 15:13:17 raspberrypi systemd[1]: caddy.service: Unit entered failed state.
Jan 02 15:13:17 raspberrypi systemd[1]: caddy.service: Failed with result ‘exit-code’.

setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy was done as per the caddy systemd howto

After a bit of fiddling into the caddy.service file I found that the culprit was this line:
; Use a minimal /dev
PrivateDevices=true

Running fine without it. Any idea why? Does that line have anything to do with the bind-to-port problem?

And, BTW, thanks to the devs for Caddy. I am a fan of golang and love using it as a web server.


(Federico Bruni) #2

Disclaimer: I’m very new to systemd.
I’ve read here that:

Note that PrivateNetwork=yes should not be used for:

Services that actually require network access (with the exception of daemons only needing socket activation)

Perhaps caddy.service falls into this category?


(Federico Bruni) #3

Sorry, wrong quote. I meant to quote this:

Note that PrivateDevices=yes should not be used for:

  1. Services that actually require physical device access
  2. Services which may be used to execute arbitrary user or administrator supplied programs (such as cron, …). We shouldn’t limit what people can do with these services.
  3. This option creates a new file system namespace where mount/umount propagation is turned off back into the host. This means that mounts made by the service will stay private to the service. Thus this option should not be used by services which shall be able to establish mounts in the host.

(Jean-Luc Lacroix) #4

Ok. Thanks for the link. It is not specific to the RPI, I just bumped into the same problem on a VPS instance. Probably for the same reason.


(Kevin Kub) #5

Can you show us your caddy.service file?

I am quite happy with this one from https://aur.archlinux.org/cgit/aur.git/tree/caddy.service?h=caddy

[Unit]
Description=Caddy HTTP/2 web server
Documentation=https://caddyserver.com/docs
After=network.target

[Service]
User=http
Group=http
Environment=CADDYPATH=/var/lib/caddy
EnvironmentFile=-/etc/caddy/envfile
ExecStart=/usr/bin/caddy -log stdout -agree -conf /etc/caddy/caddy.conf -root /tmp
ExecReload=/usr/bin/kill -USR1 $MAINPID
LimitNOFILE=1048576
LimitNPROC=64
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/caddy /var/log/caddy
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

(Jean-Luc Lacroix) #6

Here is mine (a cc from github)

[Unit]
Description=Caddy HTTP/2 web server
Documentation=https://caddyserver.com/docs
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]
Restart=on-abnormal
User=www-data
Group=www-data
Environment=CADDYPATH=/etc/ssl/caddy
ExecStart=/usr/local/bin/caddy -log stdout -agree=true -conf=/etc/caddy/Caddyfile -root=/var/tmp
ExecReload=/bin/kill -USR1 $MAINPID
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWriteDirectories=/etc/ssl/caddy

[Install]
WantedBy=multi-user.target

(Magikstm) #7

Related to: https://github.com/mholt/caddy/issues/1853

@matt as it is hard to investigate and hinders usage I would suggest:

  1. Adding more details above it and disabling it by default here:
    https://github.com/mholt/caddy/blob/c026e2b734f2ecc2f23fd91cd858018473a2a6c9/dist/init/linux-systemd/caddy.service

  2. Adding details about the added security it may provide as well as the possible issues here:
    https://github.com/mholt/caddy/tree/c026e2b734f2ecc2f23fd91cd858018473a2a6c9/dist/init/linux-systemd

I think it would help users setupping Caddy with systemd. Could an issue and a PR for it be created?


(Matt Holt) #8

I really want to keep the Caddy repo as free from system admin-related issues as much as possible, and keep it focused on Caddy itself. But we can make changes to the dist/init files for the better in the meantime; just submit a pull request. :slight_smile:


(Magikstm) #9

Thanks.

I created this PR for it: https://github.com/mholt/caddy/pull/1990


(Kevin Kub) #10

@JeanLucLacroix Please try to add this line to your service definition (probably right after [Service]:

AmbientCapabilities=CAP_NET_BIND_SERVICE

This will allow the service to bind to any port (e.g. 80 and 443).


(Jean-Luc Lacroix) #11

Yes, it works without any error message with that systemd directive . Thanks. But it works also without the PrivateDevices=true directive. I don’t know which solution is better:

AmbientCapabilities=CAP_NET_BIND_SERVICE
PrivateDevices=true

or

PrivateDevices=false

P.S. Just ran kind of benchmark and the version with PrivateDevices=false runs marginally faster (3%). Tested with ab -n3000 -c200


(Matthew Fay) #12

PrivateDevices hides physical devices under /dev from the service’s process.

There’s a system call filter and bind mounts involved, might explain the slight slowdown while it’s enabled?

https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateDevices=

Up to you if you think hiding disks and other devices from Caddy is a reasonable security measure. Personally I don’t think it’s necessary, given that Caddy is open source and doesn’t interact directly with your devices anyway.


(system) #13

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.