Caddy is a powerful web server with automatic HTTPS. I use it to serve my Quartz digital garden.

Installation

Arch Linux:

sudo pacman -S caddy

Docker:

docker pull caddy:latest

Binary: Download from https://caddyserver.com/download

Basic Configuration

Caddyfile location: /etc/caddy/Caddyfile

Serve Static Files

garden.example.com {
    root * /var/www/garden/public
    file_server
    
    # Handle SPA routing (if using Quartz SPA mode)
    try_files {path} {path}/ /index.html
    
    # Compression
    encode gzip zstd
}

With Reverse Proxy

If running Quartz dev server:

garden.example.com {
    reverse_proxy localhost:8080
}

Automatic HTTPS

Caddy automatically provisions TLS certificates via Let’s Encrypt. Just use a domain name and Caddy handles the rest.

Requirements:

  • Domain DNS points to your server
  • Ports 80 and 443 accessible
  • Caddy can bind to those ports

Running Caddy

systemd

sudo systemctl enable --now caddy

Manual

caddy run --config /etc/caddy/Caddyfile

Reload config

sudo systemctl reload caddy
# or
caddy reload --config /etc/caddy/Caddyfile

Digital Garden Setup

My Caddyfile for serving Quartz:

garden.example.com {
    root * /var/www/garden/public
    file_server
    
    # Quartz SPA routing
    try_files {path} {path}.html {path}/ /index.html
    
    # Compression for faster loads
    encode gzip zstd
    
    # Cache static assets
    @static {
        path *.css *.js *.woff2 *.png *.jpg *.svg
    }
    header @static Cache-Control "public, max-age=31536000"
    
    # Security headers
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        Referrer-Policy strict-origin-when-cross-origin
    }
}

Deployment Workflow

  1. Build Quartz: npx quartz build
  2. Copy to server: rsync -avz public/ server:/var/www/garden/public/
  3. Caddy automatically serves the new files

Or use a CI/CD pipeline to automate.

Multiple Sites

garden.example.com {
    root * /var/www/garden/public
    file_server
}
 
blog.example.com {
    root * /var/www/blog
    file_server
}
 
api.example.com {
    reverse_proxy localhost:3000
}

Resources