diff --git a/dist/init/linux-systemd/README.md b/dist/init/linux-systemd/README.md index e18f7524..908954c6 100644 --- a/dist/init/linux-systemd/README.md +++ b/dist/init/linux-systemd/README.md @@ -1,40 +1,79 @@ # systemd unit for caddy -Please do not hesitate to ask [me](mailto:klingt.net+caddy@gmail.com) if you've any questions. +Please do not hesitate to ask if you have any questions. ## Quickstart -- install the unit configuration file: `cp caddy@.service /etc/systemd/system` -- reload the systemd daemon: `systemctl deamon-reload` -- make sure to [configure](#configuration) the service unit before starting caddy -- start caddy: `systemctl start caddy@someuser` -- enable the service (automatically start on boot): `systemctl enable caddy@someuser` -- the `.caddy` folder will be created inside the users home directory that runs caddy, i.e. `/home/someuser/.caddy` for `systemctl start caddy@someuser` +The provided unit file assumes that you want to run caddy as `www-data` and group `www-data`, +both having UID and GID 33 here. +Adjust this to your liking according to the preferences of you Linux distribution! + +```bash +groupadd -g 33 www-data +useradd \ + -g www-data --no-user-group \ + --home-dir /var/www --no-create-home \ + --shell /usr/sbin/nologin \ + --system --uid 33 www-data + +mkdir /etc/caddy +chown -R root:www-data /etc/caddy +mkdir /etc/ssl/caddy +chown -R www-data:root /etc/ssl/caddy +chmod 0770 /etc/ssl/caddy +``` + +- Install the unit configuration file: `cp caddy.service /etc/systemd/system/` +- Reload the systemd daemon: `systemctl daemon-reload` +- Make sure to [configure](#configuration) the service unit before starting caddy. +- Start caddy: `systemctl start caddy.service` +- Enable the service (automatically start on boot): `systemctl enable caddy.service` +- A folder `.caddy` will be created inside the home directory of the user that runs caddy; + you can change that by providing an environment variable `HOME`, + i.e. `Environment=HOME=/var/lib/caddy` will result in `/var/lib/caddy/.caddy`. ## Configuration -- do not edit the systemd unit directly, use systemd's builtin tools: - - `systemctl edit caddy@` to make user local modifications to the service unit - - `systemctl edit --full caddy@` to make system-wide modifications -- in most cases it's enough to adapt the `ExecStart` directive: - - `systemctl edit caddy@` - - systemd needs absolute paths, therefore make sure that the path to caddy is correct +- Do not edit the systemd unit file directly. Instead, use systemd's builtin tools: + - `systemctl edit caddy.service` to make user-local modifications + - `systemctl edit --full caddy.service` for system-wide ones +- In most cases it is enough to override the `ExecStart` directive. + - systemd needs absolute paths, therefore make sure that the path to caddy is correct. - example: ```ini [Service] -; reset the original setting +; an empty value clears the original (and preceding) settings ExecStart= ExecStart=/usr/bin/caddy -conf="/etc/caddy/myCaddy.conf" -agree -email="my@mail.address" ``` -- to view your configuration use `systemctl cat caddy@` -- double check the permissions of your web root path to make sure that caddy can access it as its run user and group +- To view the resulting configuration use `systemctl cat caddy` +- Double check permissions of your *document root* path. + The user caddy runs as needs to have access to it. For example: + +```bash +# caddy would run as www-data:www-data +# serving, in this example: /var/www + +sudo -u www-data -g www-data -s \ + ls -hlAS /var/www +``` ## Tips -- use `log stdout` and `errors stderr` in your Caddyfile to make use of `journalctl` -- `journalctl` is systemd's log query tool -- lets say you want all the log entries for caddy since the last boot beginning from the last entry: `journalctl --reverse --boot --unit caddy@someuser` -- maybe you want to follow caddys log output: `journalctl -fu caddy@someuser` -- to send a signal to a service units main PID, e.g. let caddy reload its config: `systemctl kill --signal=USR1 caddy@someuser` +- Use `log stdout` and `errors stderr` in your Caddyfile to utilize `journalctl`. +- `journalctl` is systemd's log query tool. +- Let's say you want all the log entries since the last boot, beginning from the last entry: + `journalctl --reverse --boot --unit caddy.service` +- To follow caddy's log output: `journalctl -fu caddy.service` +- Send a signal to a service unit's main PID, e.g. have caddy reload its config: + `systemctl kill --signal=USR1 caddy.service` +- If you have more files that start with `caddy` – like a `caddy.timer`, `caddy.path`, or `caddy.socket` – then it is important to append `.service`. + Although if `caddy.service` is all you have, then you can just use `caddy` without any extension, such as in: `systemctl status caddy` + +- You can make your other certificates and private key files accessible to a user `www-data` by command `setfacl`, if you must: + +```bash +setfacl -m user:www-data:r-- /etc/ssl/private/my.key +``` diff --git a/dist/init/linux-systemd/caddy.service b/dist/init/linux-systemd/caddy.service new file mode 100644 index 00000000..aa5020eb --- /dev/null +++ b/dist/init/linux-systemd/caddy.service @@ -0,0 +1,50 @@ +[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-failure + +; User and group the process will run as. +User=www-data +Group=www-data + +; Letsencrypt-issued certificates will be written to this directory. +Environment=HOME=/etc/ssl/caddy + +; Always set "-root" to something safe in case it gets forgotten in the Caddyfile. +ExecStart=/usr/bin/caddy -log stdout -agree=true -conf=/etc/caddy/Caddyfile -root=/var/tmp +ExecReload=/bin/kill -USR1 $MAINPID + +; Limit the number of file descriptors; see `man systemd.exec` for more limit settings. +LimitNOFILE=1048576 +; Unmodified caddy is not expected to use more than that. +LimitNPROC=64 + +; Use private /tmp and /var/tmp, which are discarded after caddy stops. +PrivateTmp=true +; Use a minimal /dev +PrivateDevices=true +; Hide /home, /root, and /run/user. Nobody will steal your SSH-keys. +ProtectHome=true +; Make /usr, /boot, /etc and possibly some more folders read-only. +ProtectSystem=full +; … except /etc/ssl/caddy, because we want Letsencrypt-certificates there. +; This merely retains r/w access rights, it does not add any new. Must still be writable on the host! +ReadWriteDirectories=/etc/ssl/caddy + +; Drop all other capabilities. Important if you run caddy as privileged user (which you should not). +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +; … but permit caddy to open ports reserved for system services. +; This could be redundant here, but is needed in case caddy runs as nobody:nogroup. +AmbientCapabilities=CAP_NET_BIND_SERVICE +; … and prevent gaining any new privileges. +NoNewPrivileges=true + +; Caveat: Some plugins need additional capabilities. Add them to both above lines. +; - plugin "upload" needs: CAP_LEASE + +[Install] +WantedBy=multi-user.target diff --git a/dist/init/linux-systemd/caddy@.service b/dist/init/linux-systemd/caddy@.service deleted file mode 100644 index 0baaac10..00000000 --- a/dist/init/linux-systemd/caddy@.service +++ /dev/null @@ -1,23 +0,0 @@ -; see `man systemd.unit` for configuration details -; the man section also explains *specifiers* `%x` - -[Unit] -Description=Caddy HTTP/2 web server %I -Documentation=https://caddyserver.com/docs -After=network-online.target -Wants=network-online.target -Wants=systemd-networkd-wait-online.service - -[Service] -; run user and group for caddy -User=%i -Group=http -ExecStart=/usr/bin/caddy -agree=true -conf=/etc/caddy/Caddyfile -Restart=on-failure -; create a private temp folder that is not shared with other processes -PrivateTmp=true -; limit the number of file descriptors, see `man systemd.exec` for more limit settings -LimitNOFILE=8192 - -[Install] -WantedBy=multi-user.target