In a previous blogpost I explained how to run Caddy (a brilliant and simple web server) as a service using Upstart. Systemd, however, replaced Upstart on most of the operating systems, so it makes more sense to have a guide for systemd.
Caddy executable
We don’t run Caddy as root to keep things as secure as possible. To allow a non-root user to listen on port 80 or 443, we must allow the executable to do so:
$ sudo setcap cap_net_bind_service=+ep ./caddy
systemd unit file
Now we create a systemd configuration file /etc/systemd/system/caddy.service, which looks like this on my server:
[Unit]
Description=Caddy webserver
Documentation=https://caddyserver.com/
After=network.target
[Service]
User=mathias
#Group=some_group
WorkingDirectory=/home/mathias
LimitNOFILE=4096
PIDFile=/var/run/caddy/caddy.pid
ExecStart=/home/mathias/caddy -agree -email my_lets_encrypt@mail.com -pidfile=/var/run/caddy/caddy.pid
Restart=on-failure
StartLimitInterval=600
[Install]
WantedBy=multi-user.target
A brief explanation of the directives:
After=network.targetwill automatically start Caddy after all networking stuff is loaded at boot.User,GroupandWorkingDirectoryspeak for themselves… Make sure that your Caddyfile is in the working directory. You can always manually specify the location of the Caddyfile:$ caddy -conf="/path/to/Caddyfile".LimitNOFILE=4096sets max file descriptor (to a good production value), like you would do withulimit -n 4096in your terminal.ExecStartis the actual script that will be executed. In this case it runs the Caddy binary which is in my home directory, agrees the Let’s Encrypt user agreement, and sets a default email for your Let’s Encrypt account. If you don’t add those two flags, Caddy will prompt for user input, which will naturally not work when you start it as a daemon.Restart=on-failurewill automatically respawn the Caddy process if Caddy crashes (i.e. stopping with non-zero exit code).StartLimitInterval=600makes sure that if Caddy crashes too many times (being 5 by systemd’s default value) it will wait 10 min before trying again.WantedByspecifies a target we want this service to be included with.
Make sure too take a peak at the systemd documentation, since it’s very powerful and supports a lot of features!
Running the service
After you have created the service file, you must enable it: sudo systemctl enable caddy. Don’t forget to reload the service file if you make changes to it: systemctl daemon-reload.
Now you can start Caddy using sudo service caddy start. And of course stop, restart, …
You can view the status of your service using sudo service caddy status.
Ok but where do you save the systemd file?
Good question 🙂
systemd configuration must be saved in
/etc/systemd/system/caddy.service.Works perfectly, thanks!
Great post! Just wondering why PID file is in there twice? PIDFile and pidfile? 🙂
Wrong copy paste I guess… ?
Thanks for noticing!
Nope, it’s just the word wrapping… The second PID is part of the Caddy arguments:
ExecStart=/home/mathias/caddy -agree -email my_lets_encrypt@mail.com -pidfile=/var/run/caddy/caddy.pidThank you, quality article. I had caddy configured and auto booting in no time!
More detailed service file here: https://github.com/mholt/caddy/blob/master/dist/init/linux-systemd/caddy.service
I had trouble getting this working, it didn’t want to start or restart. This was the status:
“`
$ sudo service caddy status
● caddy.service – Caddy webserver
Loaded: loaded (/etc/systemd/system/caddy.service; enabled; vendor preset: enabled)
Active: inactive (dead) (Result: exit-code) since Sun 2016-09-11 02:23:28 CEST; 8min ago
Docs: https://caddyserver.com/
Process: 2133 ExecStart=/usr/local/bin/caddy -agree -email=mymail -pidfile=/var/run/caddy/caddy.pid
Main PID: 2133 (code=exited, status=1/FAILURE)
Sep 11 02:23:28 peteruithoven systemd[1]: caddy.service: Main process exited, code=exited, status=1/FAILURE
Sep 11 02:23:28 peteruithoven systemd[1]: caddy.service: Unit entered failed state.
Sep 11 02:23:28 peteruithoven systemd[1]: caddy.service: Failed with result ‘exit-code’.
Sep 11 02:23:28 peteruithoven systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Sep 11 02:23:28 peteruithoven systemd[1]: Stopped Caddy webserver.
Sep 11 02:23:28 peteruithoven systemd[1]: caddy.service: Start request repeated too quickly.
Sep 11 02:23:28 peteruithoven systemd[1]: Failed to start Caddy webserver.
“`
Since it complained about restart to quickly and I didn’t find the `StartLimitInterval` property in the docs I replaced that with a `RestartSec`:
“`
RestartSec=1s
“`
THANK YOU FOR THIS!!!!! I’ve been beating my head against the keyboard trying to figure out why this keeps happening for what it seems only me.
Hi just made an update of ubuntu 14 to 16… 🙂 I used upstart but this isn’t working any more. At the moment I figure out what to do. Do you know what to do with this error?
caddy.service – Caddy HTTP/2 web server
Loaded: loaded (/etc/systemd/system/caddy.service; enabled; vendor preset: enabled)
Active: inactive (dead) (Result: exit-code) since Do 2017-06-15 15:44:24 CEST; 3s ago
Docs: https://caddyserver.com/docs
Process: 2076 ExecStart=/usr/local/bin/caddy -log stdout -agree=true -conf=/etc/caddy/Caddyfile -root=/var/tmp (code=exited, status=203/EXEC)
Main PID: 2076 (code=exited, status=203/EXEC)
Jun 15 15:44:23 v22016043535433702 systemd[1]: caddy.service: Unit entered failed state.
Jun 15 15:44:23 v22016043535433702 systemd[1]: caddy.service: Failed with result ‘exit-code’.
Jun 15 15:44:24 v22016043535433702 systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Jun 15 15:44:24 v22016043535433702 systemd[1]: Stopped Caddy HTTP/2 web server.
Jun 15 15:44:24 v22016043535433702 systemd[1]: caddy.service: Start request repeated too quickly.
Jun 15 15:44:24 v22016043535433702 systemd[1]: Failed to start Caddy HTTP/2 web server.
Is this the complete error? Because I don’t see an error message from Caddy.
in the meantime I tried a few changes. But when I look into journalct I have this: Jun 15 17:34:27 v22016043535433702 systemd[1]: Started Caddy webserver.
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Main process exited, code=exited, status=203/EXEC
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Unit entered failed state.
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Failed with result ‘exit-code’.
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Jun 15 17:34:27 v22016043535433702 systemd[1]: Stopped Caddy webserver.
Jun 15 17:34:27 v22016043535433702 systemd[1]: Started Caddy webserver.
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Main process exited, code=exited, status=203/EXEC
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Unit entered failed state.
Jun 15 17:34:27 v22016043535433702 systemd[1]: caddy.service: Failed with result ‘exit-code’.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Stopped Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Started Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[3405]: caddy.service: Failed at step EXEC spawning /usr/local/bin/caddy: Permission denied
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Main process exited, code=exited, status=203/EXEC
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Unit entered failed state.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Failed with result ‘exit-code’.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Stopped Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Started Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Main process exited, code=exited, status=203/EXEC
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Unit entered failed state.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Failed with result ‘exit-code’.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Stopped Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Started Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Main process exited, code=exited, status=203/EXEC
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Unit entered failed state.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Failed with result ‘exit-code’.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Service hold-off time over, scheduling restart.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Stopped Caddy webserver.
Jun 15 17:34:28 v22016043535433702 systemd[1]: caddy.service: Start request repeated too quickly.
Jun 15 17:34:28 v22016043535433702 systemd[1]: Failed to start Caddy webserver.
Thats the log for the last try. Maybe some permissions problems.
EXEC spawning /usr/local/bin/caddy: Permission deniedIs Caddy executable? Has the user you’re running it under permission to launch it?
Maybe try it by hand…
yes by hand it’s working… The permissions on /usr/local/bin/caddy has to be root right?
If you can run it by hand, it should work with Systemd.
Are you sure Systemd is running it as the same user?
manuel I start caddy with /usr/local/bin/caddy: sudo ./caddy -conf=”/etc/caddy/Caddyfile” (
-rwxr-xr-x 1 root root 23092163 Jun 15 15:10 caddy
It works fine.
With systemd it is not working.
-rw-r–r– 1 root root 440 Jun 15 20:44 caddy.service
I’ve
tried your caddy.service file above and the one directly from github.
But it’s not working. What does “(code=exited, status=200/CHDIR)” mean?
The working director is specified in my file like:
WorkingDirectory=/usr/local/bin/caddy -conf=”/etc/caddy/Caddyfile” Is
this correct?