Caddy on Raspbian, A Layman's Tutorial

Let’s be honest, Caddy doesn’t “just work”. The website and tutorials are akin to, “Here’s a car. It just works! Oh, by the way, you’ll need to build and install an engine before you can drive it. Duh.”

Many thanks to all the users who helped steer me in the right direction. For the record, @matt, “have you tried turning it off and back on again” … not helpful. Stick to developing Caddy. We love you for that. The following tutorial makes a few assumptions:

  • You want Caddy to run automatically on boot
  • Your Pi is running Raspbian Stretch or Raspbian Stretch Lite (released late 2017)
  • You’re hosting a web server at home, forwarding ports 80 and 443 from your router
  • You’re using a real, fully qualified domain (e.g.
  • You own your domain’s SSL certificate and key
  • Enter commands as root or with sudo
  • Example IP
  1. Prepare your files.
mkdir /etc/ssl/caddy /etc/caddy /var/www

Add your certificates to /etc/ssl/caddy
Add your website files (HTML, CSS, JS, etc) to /var/www/mysite

If your certificate authority provides root and intermediate certificates, cat them into a single bundle, but make sure the BEGIN and END statements are on their own lines. Read more about bundles here. Example:

cat mysite.crt Root.crt Intermediate.crt > mysite_bundle.pem
  1. Download Caddy. The RPi 3, Zero, and Zero W should have ARM6 architecture. If the tar.gz file won’t open properly, try: gzip -d [file]. Use the setcap command to allow Caddy to run on ports 80 and 443.

mv arm6 arm6.tar.gz
tar zxvf arm6.tar.gz
mv caddy /usr/local/bin/caddy
mv init/linux-systemd/caddy.service /etc/systemd/system/caddy.service

setcap 'CAP_NET_BIND_SERVICE=+eip' /usr/local/bin/caddy
  1. Caddy comes with a systemd init script to start Caddy on boot, but we need to tweak it.
nano /etc/systemd/system/caddy.service

Edit the ExecStart line from “-agree=true” to “-agree=false”, which will prevent Caddy from downloading ACME certificates (we have our own). Add the commands below to let the www-data user run the script properly.

  1. Edit your Caddyfile.
nano /etc/caddy/Caddyfile

If you need to test Caddy locally, without any domains or certifications, use the following:

localhost:2015 {
    root /var/www/local

Otherwise edit the Caddyfile for your domain:, {
}, {
    root /var/www/mysite
    tls /etc/ssl/caddy/mysite_bundle.pem /etc/ssl/caddy/mysite.key
  1. In Raspbian Stretch, the www-data user is already created and added to the www-data group by default. Simply give it ownership of the relevant files and set permissions. Refer to the Readme file under /init/linux-systemd/ in the arm6.tar.gz download for specific permissions.
chown www-data:www-data /usr/local/bin/caddy
chown www-data:www-data /etc/systemd/system/caddy.service
chown www-data:www-data /etc/caddy/Caddyfile
chown -R www-data:www-data /etc/ssl/caddy
chown -R www-data:www-data /var/www
  1. Use the following commands to enable, start, and restart the Caddy service
systemctl daemon-reload
systemctl enable caddy.service
systemctl start caddy.service

systemctl daemon-reload
systemctl restart caddy.service
  1. Use the following commands to make sure Caddy is running correctly
systemctl status caddy.service
journalctl -u caddy.service

Thanks for writing up this guide, @caddyhello. I’ve got some thoughts and recommendations for you.

I’m not sure I agree with this analogy. Caddy is web server software designed to be deployed to a large number of operating systems on different hardware architectures.

It would be more analogous to the engine itself, provided in such a way that it fits in a variety of frames… Assuming the installer knows how to connect an engine to the rest of the vehicle properly. Maybe better again to refer to it as one of the many parts of an engine. I’d say it’s still a difficult association, though.

To be unambiguous, Caddy users are expected to have an understanding of the hardware and software environment they plan to deploy Caddy in, much the same as Apache or nginx expects of their users. To say that building an engine is required is… not an honest representation, I believe.

Ignoring the directly patronizing tone of this comment (please consider the community guidelines before posting in this manner again), the comment you referenced from an earlier thread was a targeted response with a specific objective in mind: to determine whether or not there was some issue with the graceful reloading functionality that might have helped to explain your issue.

The fact that it was taken as a one-liner to fob you off in the manner of IT Crowd, instead of an intent to help diagnose and fix the problem you encountered in the course of the thread, is truly unfortunate.

This will probably end up with a similar problem to the one you encountered in the previous thread, which will require some manual editing to fix.

If I might suggest a slight modification, which should put newlines between each certificate:

cat mysite.crt <(echo) Root.crt <(echo) Intermediate.crt > mysite_bundle.pem

Unless I’m much mistaken, only one of these two is required. They both do the same thing. I’d recommend using the systemd one, because it’s more secure.

This isn’t quite accurate. The presence of the -agree flag has no bearing on how Caddy decides whether or not to contact the ACME server at all. That’s determined purely by the contents of your Caddyfile.

Also, instead of setting it to false (which has no explicit effect), you could simply remove it entirely (it’s off by default and has be specified in order to enable it, as a feature for automated environments like systemd).

I’d redir to instead. The rest are up to preference, but personally I’d use http:// and https:// instead of :80 and :443, in order to reduce ambiguity.

The rest is pretty straight forward, thanks for compiling this information.

Can someone please help me here? Can you test this and ensure it works? Rpi is not available in my country to buy and test!

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