DEV Community

Edwin Sanjo Soji
Edwin Sanjo Soji

Posted on

Mastering Edge Routing: The Definitive Caddy Reverse Proxy Guide

When exposing web applications, Docker containers, or internal services to the public internet, you need a reverse proxy. While Nginx is the legacy powerhouse, Caddy has become the modern standard due to its built-in, fully automated HTTPS and incredibly readable configuration files.

This guide will walk you through a proper installation, a basic setup that is more than enough for most solo developers, and an advanced modular setup designed for multi-user server environments.

Phase 1: The Proper Installation

Do not use the default Ubuntu package manager (apt) to install Caddy right away. The default repositories often host significantly outdated versions. Instead, we will add Caddy's official Cloudsmith repository to ensure we get the latest stable release with current security patches.

1. Install prerequisite tools:

sudo apt update
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
Enter fullscreen mode Exit fullscreen mode

2. Download and add the official Caddy GPG keys:

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
Enter fullscreen mode Exit fullscreen mode

3. Add the Caddy repository to your system:

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
Enter fullscreen mode Exit fullscreen mode

4. Install Caddy:

sudo apt update
sudo apt install caddy
Enter fullscreen mode Exit fullscreen mode

Phase 2: The Basic Setup (Enough for Most Users)

If you are running a single server with just one or two applications (like a personal portfolio and a single backend API), this basic setup is completely sufficient. You do not need to overcomplicate your architecture.

Caddy's entire routing logic lives in a single file called the Caddyfile.

1. Open the Caddyfile for editing:

sudo nano /etc/caddy/Caddyfile
Enter fullscreen mode Exit fullscreen mode

2. Replace the default text with your routing blocks:

Delete whatever is in there and write your site configuration. Here is an example of routing a domain to a Next.js app running locally on port 3000:

yourdomain.com {
    reverse_proxy 127.0.0.1:3000
}

api.yourdomain.com {
    reverse_proxy 127.0.0.1:8080
}
Enter fullscreen mode Exit fullscreen mode

3. Save the file and reload Caddy:

Press CTRL + O, then Enter to save, and CTRL + X to exit Nano. Then apply the changes:

sudo systemctl reload caddy
Enter fullscreen mode Exit fullscreen mode

Caddy will instantly request SSL certificates for your domains and securely route your traffic. If you are a solo developer with a simple setup, stop here. You are done.


Phase 3: The Modular conf.d Setup

If you are hosting dozens of services, running a complex homelab, or collaborating with a team, cramming everything into one massive Caddyfile becomes messy and dangerous. A single typo could take down every site on the server.

Instead, we split our routes into a modular directory architecture.

1. Create a directory for individual configurations:

sudo mkdir -p /etc/caddy/conf.d
Enter fullscreen mode Exit fullscreen mode

2. Edit the main Caddyfile to act as an importer:

sudo nano /etc/caddy/Caddyfile
Enter fullscreen mode Exit fullscreen mode

Replace the contents with this exact structure:

{
    # Global administrative settings can go here
    # email admin@yourdomain.com
}

# Import all individual site configurations
import conf.d/*.caddy
Enter fullscreen mode Exit fullscreen mode

Save and exit.

3. Create dedicated files for each service:

Now, whenever you add a new app, give it its own file. For example, to add code-server:

sudo nano /etc/caddy/conf.d/code-server.caddy
Enter fullscreen mode Exit fullscreen mode
code.yourdomain.com {
    reverse_proxy 127.0.0.1:8080
}
Enter fullscreen mode Exit fullscreen mode

Reload Caddy (sudo systemctl reload caddy). If you ever make a mistake in code-server.caddy, it won't break your other applications.


Phase 4: Scoped User Permissions (Zero-Downtime Reloads)

In a multi-user environment, you might have standard user accounts (like a CodexSandboxUsers group or a secondary developer account) that frequently deploy new apps. They need the ability to reload Caddy to apply their new .caddy files, but giving them full sudo access to the server is a massive security risk.

We can grant a specific user or group the exact permission to reload Caddy—and nothing else.

1. Create a dedicated sudoers rule:

[!info] Why visudo?
We use visudo instead of nano here because if you make a syntax error in a sudoers file, you can permanently lock yourself out of administrative access. visudo checks your work before saving.

sudo visudo -f /etc/sudoers.d/caddy-reload
Enter fullscreen mode Exit fullscreen mode

2. Add the scoped privilege rule:

Add this line to allow the standard ubuntu user to reload Caddy without a password (adjust the username as needed for your specific setup):

ubuntu ALL=(root) NOPASSWD: /usr/bin/systemctl reload caddy
Enter fullscreen mode Exit fullscreen mode

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

Now, when your standard user deploys a new application, they can simply type sudo systemctl reload caddy. It will execute flawlessly without prompting for a password, and without giving them the keys to your entire infrastructure.

Top comments (0)