Files

title, homepage, tagline
title homepage tagline
Caddy https://github.com/caddyserver/caddy Caddy is a fast, multi-platform web server with automatic HTTPS.

To update or switch versions, run webi caddy@stable (or @v2.4, @beta, etc).

Cheat Sheet

Caddy makes it easy to use Let's Encrypt to handle HTTPS (TLS/SSL) and to reverse proxy APIs and WebSockets to other apps - such as those written node, Go, python, ruby, and PHP.

Here's the things we find most useful:

  • Simple File & Directory Server
  • Reverse Proxy with www (and HTTPS) redirects
  • Running as a system service on
    • Linux
    • MacOS
    • Windows

How to serve a directory

caddy file-server --browse --listen :443

How to serve via Caddyfile

caddy run --config ./Caddyfile

Note: run runs in the foreground, start starts a background service (daemon) in the background.

How to serve HTTPS on localhost

Caddy can be used to test with https on localhost.

Caddyfile:

localhost {
    handle /* {
        root * ./public/
        file_server
    }
    handle /api/* {
        reverse_proxy localhost:3000
    }
}

How to serve on Linux/VPS (systemd)

  1. Create a generic Caddyfile
    mkdir -p ~/srv/caddy
    echo '
    # Generically vhost all domains pointed at this server
    https:// {
        tls {
            on_demand
        }
        handle /* {
            file_server
            root * /home/app/srv/www/{host}/public/
        }
    }
    ' > ~/srv/caddy/Caddyfile
    
  2. Install serviceman
    webi serviceman
    source ~/.config/envman/PATH.env
    
  3. Install caddy as a system service
    sudo env PATH="$PATH" \
        serviceman add --system --username "$(whoami)" --name caddy -- \
            caddy run --config ~/srv/caddy/Caddyfile
    

Note: In this example any host that points to the server and has files in ~/srv/www/{host}/public can be served without additional changes.

Note: More on using systemctl below.

How to redirect and reverse proxy

Here's what a fairly basic Caddyfile looks like:

Caddyfile:

# redirect www to bare domain
www.example.com {
    redir https://example.com{uri} permanent
}

example.com {
    ###########
    # Logging #
    ###########

    # log to stdout, which is captured by journalctl
    log {
        output stdout
        format console
    }

    ###############
    # Compression #
    ###############

    # turn on standard streaming compression
    encode gzip zstd

    ####################
    # Reverse Proxying #
    ####################

    # reverse proxy /api to :3000
    handle /api/* {
        reverse_proxy localhost:3000
    }

    # reverse proxy some "well known" APIs
    handle /.well-known/openid-configuration {
        reverse_proxy localhost:3000
    }
    handle /.well-known/jwks.json {
        reverse_proxy  localhost:3000
    }

    ##################
    # Path Rewriting #
    ##################

    # reverse proxy and rewrite path /api/oldpath/* => /api/newpath/*
    handle_path /api/oldpath/* {
        rewrite * /api/newpath{path}
        reverse_proxy localhost:3000
    }

    ###############
    # File Server #
    ###############

    # serve static files
    handle /* {
        root * /srv/example.com/public/
        file_server
    }
}
caddyfile run --config ./Caddyfile

How to rewrite and reverse proxy

example.com {
    # ...

    # reverse proxy /api/new/ to http://localhost:3100/api/
    handle_path /api/new/* {
        rewrite * /api{path}
        reverse_proxy localhost:3100
    }
}

How to start Caddy as a Linux service

Here are the 3 things you need to do to start Caddy as a system service:

a non-root user

If you don't have a non-root user, consider adding the app user with ssh-adduser.

Using a user named app to run your services is common industry convention.

port-binding privileges

You can use setcap or setcap-netbind to allow Caddy to use privileged ports.

sudo setcap cap_net_bind_service=+ep "$(readlink -f "$(command -v caddy)")"

systemd config

You can use serviceman to create and start the appropriate systemd launcher for Linux.

Install Serviceman with Webi:

webi serviceman

Use Serviceman to create a systemd config file.

sudo env PATH="$PATH" \
    serviceman add --system --username $(whoami) --name caddy -- \
        caddy run --config ./Caddyfile

This will create /etc/systemd/system/caddy.service, which can be managed with systemctl. For example:

sudo systemctl restart caddy

How to start Caddy as a MacOS Service

Port-Binding Permission

Caddy must run as the root user in order to bind to ports 80 and 443.

launchd plist

You can use serviceman to create and start the appropriate service launcher file for MacOS.

Install Serviceman with Webi:

webi serviceman

Use Serviceman to create a launchd plist file.

serviceman add --username $(whoami) --name caddy -- \
    caddy run --config ./Caddyfile

This will create ~//Library/LaunchAgents/caddy.plist, which can be managed with launchctl. For example:

launchctl unload -w "$HOME/Library/LaunchAgents/caddy.plist"
launchctl load -w "$HOME/Library/LaunchAgents/caddy.plist"

How to start Caddy as a Windows Service

You may need to update the Windows Firewall to allow traffic through to Caddy. You'll also need to create a Startup entry in the registry, which can be done with Serviceman.

Windows Firewall

You can use PowerShell to update the firewall, which looks something like this:

powershell.exe -WindowStyle Hidden -Command $r = Get-NetFirewallRule -DisplayName 'Caddy Web Server' 2> $null; if ($r) {write-host 'found rule';} else {New-NetFirewallRule -DisplayName 'Go Web Server' -Direction Inbound C:\\Users\\YOUR_USER\\.local\\bin\\caddy.exe -Action Allow}

Startup Registry

You can use Serviceman to create and start the appropriate service launcher for Windows.

Install Serviceman with Webi:

webi.bat serviceman

Use Serviceman to create a Startup entry in the Windows Registry:

serviceman.exe add --name caddy -- \
    caddy run --config ./Caddyfile

You can manage the service directly with Serviceman. For example:

serviceman stop caddy
serviceman start caddy