Set up Caddy Server on Ubuntu 24.04

By Anurag Singh

Updated on Oct 29, 2025

Set up Caddy Server on Ubuntu 24.04

In this tutorial, we'll learn how to set up Caddy Server on Ubuntu 24.04.

What is Caddy?

Caddy is a modern, open-source web server written in Go. It’s designed to be simple, secure, and fully automated. What makes Caddy special is that it automatically manages HTTPS certificates using Let’s Encrypt — no manual setup or renewal needed. It can serve static websites, act as a reverse proxy for backend apps, and handle load balancing with clean, human-readable configuration. In short, Caddy turns complex server management into a one-file setup that just works.

Prerequisites

Before we begin, ensure we have the following:

  • An Ubuntu 24.04 dedicate server or KVM VPS.
  • Basic Linux Command Line Knowledge.
  • A domain name, pointing A record to server IP.

Set up Caddy Server on Ubuntu 24.04

Step 1: Update the system

sudo apt update && sudo apt upgrade -y

Keep our system fresh so packages work properly.

Step 2: Install Caddy

Caddy provides an official repository. Run these commands to add it and install:

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 -y caddy

Caddy starts automatically after installation. Check its status:

sudo systemctl status caddy

Press q to exit the status screen.

Step 3: Add our website files

Let’s create a simple site directory.

sudo mkdir -p /var/www/example
sudo nano /var/www/example/index.html

Add a small test page:

<h1>Welcome to Our Website</h1>
<p>This site is powered by Caddy Server with HTTPS.</p>

Save and exit (Ctrl + O, Enter, Ctrl + X).

Step 4: Configure Caddy

Open the main configuration file:

sudo nano /etc/caddy/Caddyfile

Replace its content with this simple setup:

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

Important: Replace example.com with our real domain that points to the server’s public IP address.

Step 5: Allow HTTP and HTTPS traffic

If we’re using ufw (Ubuntu firewall):

sudo ufw allow 80,443/tcp
sudo ufw reload

Step 6: Reload Caddy

sudo systemctl reload caddy
  • Caddy will automatically fetch an SSL certificate from Let’s Encrypt and enable HTTPS.
  • We can check it by visiting our domain in a browser:
https://example.com

If the domain points correctly, we’ll see our test page with a lock icon — meaning SSL is working.

Step 7: Check Logs (if needed)

If the site doesn’t load:

sudo journalctl -u caddy -f

This shows what’s going on in real-time.

List active certificates and expiry:

sudo caddy list-certs

Manually trigger a reload without downtime:

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

Certificate renewals are automatic; list-certs shows expiry dates for verification.

Simple proxy with header forwarding and websockets

example.com {
    reverse_proxy {
        to localhost:3000
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-For {remote}
        header_up Host {host}
    }
}

This preserves original host/protocol and supports WebSocket upgrades automatically.

Reverse proxy with path match (proxy only /api)

example.com {
    handle_path /api/* {
        reverse_proxy localhost:8080
    }
    handle {
        root * /var/www/html
        file_server
    }
}

Simple load balancing

api.example.com {
    reverse_proxy lb1.internal:8080 lb2.internal:8080 {
        health_path /healthz
        health_interval 10s
    }
}

These patterns are standard and cover most proxy needs: path routing, static file fallback, websockets, and backend pools.

Using DNS provider for wildcard certs (short practical note)

If we need *.example.com, do the DNS challenge. Two options:

  • Download a Caddy binary with the DNS provider module from the Caddy download page.
  • Build a custom Caddy with xcaddy including caddy-dns/<provider>.

Then configure provider credentials (example Cloudflare) in env or config and use tls directive:

example.com, *.example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    reverse_proxy ... 
}

Consult the provider docs for exact environment variables and plugin names.

Security & production tips

  • Run Caddy as the packaged caddy user (default) — do not run as root. Package takes care of that.
  • Use a short health_path for backends so Caddy can detect failed backends and avoid routing to them.
  • Keep backups of /etc/caddy/Caddyfile and any TLS-related environment variables for DNS plugins.
  • For strict compliance environments, pin ACME issuer or use a private CA via tls directive.

Conclusion

We set up Caddy from the official repo, created a Caddyfile for reverse proxying apps and static content, confirmed automatic HTTPS behavior, covered wildcard/DNS challenge considerations, and included checks and production tips. Caddy removes a lot of the friction around TLS and reverse proxies; for most web apps it’s a lighter, simpler alternative to manual cert management and complex Nginx configs. Use the examples above as copy-paste templates and adapt headers/backends to our stack.