All Newbie, Semua Tentang Ilmu

Recent

How to Use Caddy as a Reverse Proxy with Automatic HTTPS

Caddy is a web server that obtains and renews TLS certificates on its own. For a reverse proxy in front of a few services, that removes most of the work: no Certbot, no renewal timer, no certificate paths in the config.

Server rack filled with a tangled mass of blue and red network cables
Foto: Kim Scarborough, CC BY-SA 2.0, via Wikimedia Commons

Ringkasan singkat

  • Automatic HTTPS with no Certbot step.
  • Headers such as X-Forwarded-For are sent for you.
  • Raise request_body max_size for uploads.
  • Validate before reload; old config stays on failure.

This guide puts Caddy in front of two local services, adds security headers, and explains the parts that can still go wrong.

Prerequisites

  • Ubuntu with a public IP and ports 80/443 reachable.
  • A DNS A record pointing to the server.
  • Services listening on localhost, for example 127.0.0.1:3000.

1. Install Caddy

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 version
systemctl status caddy --no-pager
Caddy terminating TLS and proxying to two local upstreamsInternet:80 / :443Caddyautomatic TLSCaddyfileupstream A127.0.0.1:3000upstream B127.0.0.1:8080
Diagram: Caddy terminating TLS and proxying to two local upstreams

2. Write the Caddyfile

sudo nano /etc/caddy/Caddyfile
app.example.com {
    reverse_proxy 127.0.0.1:3000
}

api.example.com {
    reverse_proxy 127.0.0.1:8080
}

That is the entire configuration. Caddy sees the hostname, requests a certificate, redirects HTTP, and proxies the request. Four lines replace a server block plus a Certbot run.

3. Validate and reload

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://app.example.com

validate catches syntax errors before they reach production. If the reload fails, Caddy keeps serving the previous configuration — useful, but it also hides mistakes, so read the output.

4. Proxy headers

Caddy forwards Host, X-Forwarded-For, X-Forwarded-Proto, and X-Real-IP automatically. Most applications therefore work without extra directives, and logs show real client addresses.

5. Uploads and timeouts

app.example.com {
    reverse_proxy 127.0.0.1:3000
    request_body {
        max_size 50MB
    }
}

Large uploads fail with 413 without this. Do not remove the limit entirely; pick a size that matches the application.

6. Security headers

app.example.com {
    reverse_proxy 127.0.0.1:3000

    header {
        Strict-Transport-Security "max-age=31536000"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server
    }
}

-Server removes the version banner from responses. HSTS should only be enabled after HTTPS is confirmed working on every subdomain you own.

7. Static files and path routing

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

    handle_path /api/* {
        reverse_proxy 127.0.0.1:8080
    }
}

handle_path strips the prefix before forwarding, which is what most APIs expect.

8. Logs

journalctl -u caddy -f
journalctl -u caddy --since "10 min ago" | grep -i error

9. Redirects and the www variant

www.example.com {
    redir https://example.com{uri} permanent
}

Pick one canonical hostname and redirect the other. Two working hostnames mean two indexed versions of the same page, which splits ranking signals instead of strengthening them.

10. Restrict access to an admin app

admin.example.com {
    basic_auth {
        admin $2a$14$HASHED_PASSWORD
    }
    reverse_proxy 127.0.0.1:9000
}

Generate the hash with caddy hash-password. Basic authentication over HTTPS is acceptable for a single operator, but a VPN remains the stronger option: it removes the login page from the public internet entirely.

11. Several upstreams and health checks

app.example.com {
    reverse_proxy 10.0.0.11:3000 10.0.0.12:3000 {
        lb_policy round_robin
        health_uri /health
        health_interval 10s
    }
}

Caddy stops sending traffic to an upstream that fails the health check and brings it back when it recovers. This is what turns two application servers into something more resilient than one, without adding a separate load balancer.

Keep the health endpoint cheap. A check that queries the database every ten seconds becomes its own incident.

Troubleshooting

SymptomCauseFix
Certificate not issuedDNS not pointing at the serverdig +short app.example.com
502 Bad GatewayUpstream down or wrong portss -lntp | grep 3000
413 on uploadDefault body limitrequest_body max_size
Config ignored after editReload not runcaddy validate then reload
Too many certificatesRepeated failed issuanceFix DNS first; use staging for tests

12. What Caddy does not do for you

It handles certificates, HTTP/2, and proxying. It does not patch applications, rate-limit abusive clients, or replace a firewall. Ports 80 and 443 still need to be open; everything else can stay closed. If you later move a service to another host, the Caddyfile is usually the only file that changes.

FAQ

Caddy or Nginx?

Caddy wins on simplicity: automatic HTTPS, few directives, readable config. Nginx has more tuning options and a larger body of guides. For a handful of self-hosted services, Caddy is usually faster to get right.

Where are certificates stored?

In Caddy's data directory, managed automatically. You never edit certificate paths.

Can it proxy WebSockets?

Yes, by default, with no extra configuration.

Does it work behind Cloudflare?

Yes. Use DNS-only while issuing the first certificate, or configure the DNS challenge if you keep the proxy enabled.





0 comments:

Post a Comment