What Is Caddy?

Caddy is a modern, open-source web server and reverse proxy written in Go. Its killer feature: automatic HTTPS with Let’s Encrypt. Unlike Nginx or Apache where you manually configure SSL certificates, Caddy obtains and renews them automatically.

Other Caddy features:

  • HTTP/2 and HTTP/3 support out of the box
  • Simple configuration with a human-readable Caddyfile
  • Built-in metrics and health checks
  • Plugin ecosystem for caching, authentication, and more

Caddy is ideal for:

  • Developers who want HTTPS without certificate management
  • Teams deploying microservices or containerized apps
  • Anyone tired of Nginx/Apache configuration complexity

What You Will Need

For this guide, you’ll need:

  • A VPS with Ubuntu 22.04 or 24.04 (we recommend a Cloud VPS from Canadian Web Hosting)
  • A domain name pointing to your server’s IP
  • Root or sudo access
  • Ports 80 and 443 open in your firewall

Our Cloud VPS plans include Canadian data centres, 24/7 support, and full root access. Caddy pairs well with other modern tools—for a comparison of web servers behind it, see our Apache vs Nginx comparison. Not comfortable managing servers? Add Managed Support—our team will handle setup and ongoing maintenance.

Step 1: Install Caddy

Caddy provides official repositories for easy installation and updates.

Ubuntu/Debian

sudo apt update
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Verify Installation

caddy version

You should see something like:

v2.8.4 h1:2hwYqi7wk2hgY3p3pR8nqPoLb6yXh+Z7pjE2k2YVpBQ=

Step 2: Basic Caddyfile Configuration

Caddy’s configuration lives in /etc/caddy/Caddyfile. Let’s create a simple configuration:

sudo nano /etc/caddy/Caddyfile

Add:

your-domain.com {
    root * /var/www/html
    file_server
}

This tells Caddy:

  • Serve your-domain.com
  • Use /var/www/html as the document root
  • Enable the file_server directive (serves static files)

Replace your-domain.com with your actual domain.

Step 3: Start Caddy and Enable Auto-HTTPS

Caddy runs as a systemd service. Start it:

sudo systemctl start caddy
sudo systemctl enable caddy

Check status:

sudo systemctl status caddy

Now visit http://your-domain.com. Caddy will:

  1. Detect the request over HTTP
  2. Obtain a Let’s Encrypt certificate automatically
  3. Redirect you to HTTPS
  4. Serve your site with a valid SSL certificate

This happens automatically on first visit. No manual certificate commands needed.

Step 4: Verify HTTPS Works

Visit https://your-domain.com. You should see a padlock in your browser’s address bar.

Check the certificate details:

openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null | openssl x509 -noout -subject -dates

You’ll see the certificate issuer (Let’s Encrypt) and expiry date (~90 days from now).

Step 5: Reverse Proxy Configuration

Caddy’s real power is as a reverse proxy. Let’s proxy to a local application running on port 3000:

your-domain.com {
    reverse_proxy localhost:3000
}

Or with multiple backends (load balancing):

your-domain.com {
    reverse_proxy localhost:3000 localhost:3001 {
        lb_policy round_robin
    }
}

Caddy handles:

  • SSL termination (HTTPS at the edge, HTTP to backend)
  • Load balancing
  • Health checks (with health_uri option)
  • WebSocket upgrades automatically

Step 6: Advanced Configuration Examples

Multiple Sites (Virtual Hosts)

site1.com {
    root * /var/www/site1
    file_server
}

site2.com {
    root * /var/www/site2
    file_server
}

API Gateway Pattern

api.your-domain.com {
    route /users/* {
        reverse_proxy localhost:4001
    }
    route /products/* {
        reverse_proxy localhost:4002
    }
    route /orders/* {
        reverse_proxy localhost:4003
    }
}

Static Site with SPA Routing

app.your-domain.com {
    root * /var/www/spa
    file_server {
        try_files {path} /index.html
    }
}

The try_files directive serves index.html for any path that doesn’t match a static file—essential for single-page applications.

Step 7: Security Hardening

1. Restrict Caddy User Permissions

Caddy runs as the caddy user. Limit its capabilities:

sudo systemctl edit caddy

Add:

[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/etc/ssl/caddy /var/lib/caddy

2. Configure Firewall

Allow only necessary ports:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

3. Rate Limiting

Prevent abuse:

your-domain.com {
    rate_limit {
        zone dynamic {
            key {remote_host}
            events 100
            window 1m
        }
    }
    reverse_proxy localhost:3000
}

4. Security Headers

Caddy adds sensible defaults. Add extra headers:

your-domain.com {
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        Referrer-Policy strict-origin-when-cross-origin
    }
    reverse_proxy localhost:3000
}

Step 8: Monitoring and Logging

Access Logs

Caddy logs to journald by default:

sudo journalctl -u caddy --since "1 hour ago"

Metrics Endpoint

Enable the metrics plugin in Caddyfile:

:2019 {
    metrics
}

Then query metrics at http://localhost:2019/metrics (Prometheus format).

Health Checks

Add a health endpoint:

your-domain.com {
    reverse_proxy localhost:3000 {
        health_uri /health
        health_interval 30s
    }
}

Step 9: Troubleshooting Common Issues

Issue: Caddy Won’t Start

Check configuration syntax:

caddy validate --config /etc/caddy/Caddyfile

Check for port conflicts:

sudo ss -tulpn | grep :80
sudo ss -tulpn | grep :443

Issue: Let’s Encrypt Certificate Not Issuing

Common causes:

  1. Domain doesn’t resolve to server IP
  2. Port 80 blocked by firewall
  3. Rate limit exceeded (too many certificate requests)

Test domain resolution:

dig your-domain.com +short

Test port 80 accessibility:

curl -I http://your-domain.com

Issue: Reverse Proxy Not Working

Check backend is running:

curl -I http://localhost:3000

Enable debug logging in Caddy:

sudo systemctl edit caddy

Add:

[Service]
Environment=CADDY_LOG_LEVEL=DEBUG

Then restart and check logs:

sudo systemctl restart caddy
sudo journalctl -u caddy -f

Step 10: Production Deployment Checklist

  1. ? Domain configured with A/AAAA records pointing to server
  2. ? Firewall configured (ports 80/443 open)
  3. ? Caddy installed from official repository
  4. ? Caddyfile validated with caddy validate
  5. ? Systemd service running and enabled
  6. ? HTTPS working (padlock in browser)
  7. ? Backend services accessible through reverse proxy
  8. ? Monitoring configured (logs, metrics, health checks)
  9. ? Backups configured for Caddyfile and certificates

Conclusion

Caddy eliminates the SSL certificate management burden that comes with Nginx or Apache. With automatic HTTPS, simple configuration, and built-in reverse proxy capabilities, it’s an excellent choice for modern web applications.

Key advantages for Canadian businesses:

  • Data sovereignty: Run Caddy on Canadian Web Hosting VPS in Vancouver or Toronto data centres
  • Compliance: Automatic HTTPS helps meet security best practices
  • Cost savings: No need for paid SSL certificates or complex configuration

Ready to deploy Caddy? Start with a Cloud VPS from Canadian Web Hosting. Need help with setup? Our Managed Support team can configure Caddy, monitor certificates, and handle ongoing maintenance.

Questions about Caddy or reverse proxy configuration? Contact our support team—we’re here 24/7.