Install Caddy Web Server on Ubuntu VPS with automatic HTTPS

What Is Caddy and Why It Is Easier Than Nginx/Apache

Caddy is a modern web server written in Go, designed with simplicity as a first-class priority. Its defining feature is automatic SSL certificate provisioning via Let's Encrypt and ZeroSSL — no Certbot installation, no cron jobs, no manual renewal steps required. Caddy handles all of this silently in the background.

Setting up Nginx with SSL involves multiple steps: installing Certbot, running certbot --nginx, verifying renewal with cron, and maintaining separate server blocks for HTTP and HTTPS. Caddy collapses all of this into a single, human-readable configuration file called the Caddyfile. A complete HTTPS-enabled site can be configured in under five lines.

Prerequisites Before Installation

Before installing Caddy, ensure the following conditions are met on your VPS:

This last point is critical: Caddy cannot issue an SSL certificate unless Let's Encrypt can reach your server on port 80. If DNS has not fully propagated yet, or if another service is already occupying port 80, the ACME challenge will fail.

Installing Caddy on Ubuntu via the Official APT Repository

Caddy's recommended installation method on Debian/Ubuntu is through its official APT repository, which ensures you receive automatic updates when new versions are released. Run the following commands in order:

# 1. Install required dependencies
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

# 2. Add Caddy's GPG signing key
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

# 3. Add the Caddy APT repository
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list

# 4. Update and install Caddy
sudo apt update
sudo apt install caddy

After installation, Caddy is automatically registered as a systemd service. Verify it is running with:

sudo systemctl status caddy

Basic Caddyfile Structure

Caddy's configuration file, the Caddyfile, lives at /etc/caddy/Caddyfile by default. The structure is block-based: each domain gets its own block containing directives. Here is a minimal example:

# /etc/caddy/Caddyfile

# Serve a static site with automatic HTTPS
example.com {
    root * /var/www/html
    file_server
}

# Redirect www to non-www
www.example.com {
    redir https://example.com{uri} permanent
}

That is all that is needed. Caddy will automatically obtain an SSL certificate for example.com, configure TLS, and redirect all HTTP traffic to HTTPS. There is no need for separate listen 80 and listen 443 blocks as in Nginx.

Caddyfile Examples: Static Sites and Reverse Proxy

Static Website with Compression and Logging

# /etc/caddy/Caddyfile

mywebsite.com {
    root * /var/www/mywebsite
    file_server
    encode gzip
    log {
        output file /var/log/caddy/mywebsite.log
    }
}

Reverse Proxy to a Node.js Application (Port 3000)

app.mywebsite.com {
    reverse_proxy localhost:3000
}

Reverse Proxy to PHP-FPM

php.mywebsite.com {
    root * /var/www/phpapp
    php_fastcgi unix//run/php/php8.2-fpm.sock
    file_server
}

Reverse Proxy to a Python/Flask Application (Port 5000)

api.mywebsite.com {
    reverse_proxy localhost:5000 {
        header_up Host {host}
        header_up X-Real-IP {remote}
    }
}

Multiple domains can be served from a single Caddyfile by stacking blocks. Caddy issues a separate SSL certificate for each domain automatically, making it straightforward to host multiple applications on a single VPS.

Caddy vs Nginx vs Apache: Side-by-Side Comparison

Choosing a web server comes down to trade-offs between ease of configuration, raw performance, and ecosystem maturity. The table below summarises the key differences:

Feature Caddy Nginx Apache
Automatic SSL Built-in Requires Certbot Requires Certbot
Config Complexity Very simple Moderate Moderate–complex
HTTP/3 (QUIC) Built-in Extra configuration Extra module
Raw Performance Good Excellent Good
Plugin Ecosystem Limited Extensive Largest
Beginner Friendly Best Moderate Moderate

In summary: choose Caddy when you want HTTPS working immediately with minimal configuration. Choose Nginx when raw throughput is a priority and your team is comfortable with server administration. Choose Apache when you need the broadest compatibility or rely heavily on .htaccess rules.

Advanced Caddyfile Configuration: Headers, Auth, and Logging

Beyond serving files and proxying traffic, Caddy provides built-in directives for security hardening and observability that require no additional modules.

Adding Security Headers

mywebsite.com {
    root * /var/www/mywebsite
    file_server
    header {
        # Prevent clickjacking
        X-Frame-Options "SAMEORIGIN"
        # Enforce HTTPS for one year
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        # Stop MIME-type sniffing
        X-Content-Type-Options "nosniff"
        # Remove server fingerprint
        -Server
    }
}

Protecting an Admin Area with Basic Authentication

First generate a bcrypt password hash using caddy hash-password, then reference it in the Caddyfile:

admin.mywebsite.com {
    reverse_proxy localhost:8080
    basicauth {
        # username: admin, hash from: caddy hash-password
        admin JDJhJDEyJGF....(hash)
    }
}

Structured JSON Logging for Production

{
    log {
        format json
        output file /var/log/caddy/access.log {
            roll_size 100mb
            roll_keep 5
        }
    }
}

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

The global block (the braces before any site block) applies settings across all sites in the Caddyfile. The roll_size and roll_keep options rotate logs automatically to prevent disk exhaustion in production.

Monitoring Caddy and Diagnosing Common Issues

Maintaining a Caddy installation in production involves periodically checking certificate health and understanding the log output when errors occur.

Checking Certificate Status

# List all certificates managed by Caddy
sudo caddy list-certificates

# Validate Caddyfile syntax before applying changes
sudo caddy validate --config /etc/caddy/Caddyfile

Key Diagnostic Commands

Forcing Certificate Renewal Manually

# Stop Caddy to release port 80, then force renewal
sudo systemctl stop caddy
sudo caddy run --config /etc/caddy/Caddyfile &
# Caddy will attempt to renew all certificates on startup
# Then return to normal service mode
sudo systemctl start caddy

Manual renewal is rarely necessary since Caddy handles renewal automatically 30 days before expiry. The above steps are useful if a certificate has already expired and the automatic process has been interrupted by an extended service outage.

Managing Caddy with systemctl

Since Caddy runs as a systemd service, all management is done with standard systemctl commands:

# Start Caddy
sudo systemctl start caddy

# Stop Caddy
sudo systemctl stop caddy

# Reload configuration after editing the Caddyfile (no restart needed)
sudo systemctl reload caddy

# Check service status and recent logs
sudo systemctl status caddy

# Stream logs in real time
sudo journalctl -u caddy -f

# Enable Caddy to start automatically on server reboot
sudo systemctl enable caddy

The most frequently used command is sudo systemctl reload caddy after editing the Caddyfile. Unlike a full restart, a reload applies the new configuration gracefully without terminating existing connections, making it safe to use in production environments.

Important: Domain Must Point to Your VPS Before SSL Can Be Issued

Caddy's automatic HTTPS relies on the ACME HTTP-01 challenge, which requires Let's Encrypt to make an HTTP request to port 80 of your server. SSL issuance will fail if any of the following conditions exist:

If you encounter ACME-related errors, inspect the Caddy logs with sudo journalctl -u caddy -n 50 to identify the root cause, fix the issue, then reload Caddy to retry certificate issuance.

Key advantage: Caddy automatically renews SSL certificates every 60 days. No cron jobs, no Certbot commands, no manual intervention. As long as the Caddy service is running and the domain remains reachable, certificates will be renewed before expiry — removing one of the most common sources of unexpected HTTPS outages.

Deploy Caddy on AsiaGB VPS

AsiaGB VPS plans start from 500 THB/month with a dedicated public IP, Ubuntu support, and open ports 80/443 — everything you need to run Caddy and serve your applications over HTTPS immediately.

View VPS Plans