Installing Caddy as a service in your cloud instance

Caddy should be everyone’s server of choice. Especially lazy people, and that’s everyone. This blog is served by Caddy. It is a modern web server written in Go. It does automatic HTTPS configuration. TF is automatic you ask? Take this blog for example – if it were to run in Nginx, the config file would look like this:

http {

   server {
      listen 80 default_server;
      listen [::]:80 default_server;
      return 301 https://$host$request_uri;
   }

   server {
      default_type application/octet-stream;
      include /etc/nginx/mime.types;
      gzip on;
      gzip_types text/plain application/xml;
      root /var/www/html;
      index.php index.html;
      listen       443 ssl http2;
      server_name  blog.jitdor.com;
      ssl_certificate         /etc/somecert.pem;
      ssl_certificate_key     /etc/somekey.pem;
      ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
      ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
      ssl_prefer_server_ciphers on;
      ssl_session_cache shared:SSL:10m;
      ssl_session_timeout 10m;
      error_page 497  https://$host$request_uri;

      location ~ .php$ {
         fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
      }
   }
}

And you’ll have to separately deal with the SSL certificates using Certbot or other means. Now let’s like a look at the equivalent Caddy configuration file:

blog.jitdor.com {
   gzip
   root /var/www/html
   fastcgi / /run/php/php7.4-fpm.sock php
}

At launch, Caddy would acquire the signed SSL certificate for you automatically and set up a cron job to renew the certificate periodically. Talk about set and forget. Sweet.

However, you can’t install Caddy using APT. You can install it via the Snap Store using the pre-release channel flag:

snap install --edge caddy

But I don’t like pre-release shit and the Snap Store version is not always the latest. So we are going to do it from scratch.

First, run the official install script. I have also opted to install the Cloudflare DNS plugin:

curl https://getcaddy.com | bash -s personal tls.dns.cloudflare

For Caddy to be able to serve web requests, you will need to allow the Caddy binary to bind to ports less than 1024:

setcap cap_net_bind_service=+ep /usr/local/bin/caddy

We will then need to create the necessary directories, config file and assign the proper permissions:

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
touch /etc/caddy/Caddyfile
mkdir /var/www
chown www-data: /var/www

Then we will create a systemd service file /etc/systemd/system/caddy.service with the following contents:

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

[Service]
Restart=on-failure
StartLimitInterval=86400
StartLimitBurst=5
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
LimitNOFILE=1048576
LimitNPROC=64
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=full
ReadWriteDirectories=/etc/ssl/caddy
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Then enable Caddy as a system service:

systemctl enable caddy.service

Finally, create or unpack your website files to /var/www/yoursite.com and update the Caddy config file at /etc/caddy/Caddyfile then you are good to go

yoursite.com {
     root /var/www/yoursite.com
}

Comments

Leave a Reply