Networking & EdgeGrid Pulsar team··8 min read

Caddy vs Nginx in 2026: Choose Your VPS Reverse Proxy

Choose Caddy or Nginx for a single Ubuntu 24.04 LTS VPS, compare HTTPS and proxy behavior, and learn what to verify before changing your production edge.

Caddy vs Nginx in 2026: Choose Your VPS Reverse Proxy featured image
On this page
Short answer

Choose Caddy for a new single-VPS application when you want automatic HTTPS and a small reverse proxy configuration. Keep Nginx when you already operate it confidently or depend on its proxy caching and routing rules. On Ubuntu 24.04 LTS, we default to Caddy for a fresh setup, but would not replace a working Nginx installation just to shorten its configuration.

Choose around the work you need to maintain

You are choosing which service will accept public traffic and forward it to your application. We recommend Caddy for a fresh Ubuntu 24.04 LTS VPS, while keeping Nginx where its existing configuration already meets your needs.

The difference that matters on a small server is how much configuration you must understand when something breaks. Caddy makes an ordinary HTTPS application straightforward to describe. Nginx earns its place when you need its specific controls or already have a maintenance procedure your team understands.

Your situationOur choiceReason
New application behind a public hostnameCaddyAutomatic HTTPS and concise upstream routing
Working Nginx deployment with understood configurationKeep NginxA migration adds work without necessarily fixing anything
Proxy response caching with detailed cache rulesNginxBuilt-in proxy cache directives
Existing Nginx modules or complicated location rulesNginxPreserve required behavior until you can replace it deliberately
Ordinary app routing without special edge requirementsCaddyLess configuration to review for the common case

Neither choice makes the VPS highly available. Both can distribute requests across application instances, but instances on the same host still fail together when that host disappears. If those responsibilities are getting mixed together, read where reverse proxies, load balancers and CDNs belong before adding another component.

Decide who owns certificate renewal

Caddy automatically obtains and renews certificates for qualifying public hostnames and adds HTTP-to-HTTPS redirects. You still supply correct DNS and reachable validation endpoints, and preserve writable certificate storage. These requirements are documented in Caddy's automatic HTTPS guide.

For a conventional Nginx installation on Ubuntu 24.04 LTS, we would plan an explicit certificate workflow, commonly using Certbot. Document how renewal runs and how Nginx loads a renewed certificate. Treat that workflow as part of the service, with an owner and a failure alert.

The blanket claim that Nginx cannot automate certificates is outdated. Nginx also has an ACME module for automatic certificate management, but module availability and configuration depend on your installation. Do not assume an upstream feature is present in the package already running on your VPS.

For either server, monitor certificate expiry from outside the machine. A running process does not prove that renewal can complete, particularly after a DNS or firewall change. Keep private keys out of your application repository and restrict access to their backups.

Start a Caddy reverse proxy with one explicit upstream

Assume Caddy is installed as a systemd service and your application already listens on 127.0.0.1:3001. The following belongs in /etc/caddy/Caddyfile; replace app.example.com with a hostname you control before using it. If the application is not yet running reliably, complete your application deployment on a VPS first.

caddyfile
app.example.com {
    reverse_proxy 127.0.0.1:3001
}

Point the hostname's A record at the VPS, and publish an AAAA record only when its address actually reaches this server. Permit inbound TCP traffic on ports 80 and 443 through both the host firewall and any provider firewall. Confirm that Caddy can own those listeners before applying the configuration.

For this HTTP upstream, Caddy preserves the incoming host and supplies forwarded headers without extra header directives. WebSocket proxying is supported by the same handler. The Caddy reverse proxy reference explains these defaults and the controls available when your application needs different behavior.

Keep the application listener private so clients cannot bypass the proxy. If Caddy runs inside a container, 127.0.0.1 refers to that container, so use the application's service name on a shared private network instead. Follow the networking checks in the Docker Compose production checklist before publishing container ports.

Choose Nginx when its controls solve a real requirement

Nginx gives you explicit proxy buffering and response caching controls. Those are useful when you can describe the behavior you need, such as caching public responses while excluding authenticated requests. The Nginx proxy module documentation covers the directives and their defaults.

This loopback-only Nginx server block illustrates the same upstream mapping, with forwarded headers set explicitly. It belongs inside the http configuration context, such as an included file under /etc/nginx/conf.d/. It is a local HTTP comparison; a public deployment also needs its HTTPS listener and certificate workflow.

nginx
server {
    listen 127.0.0.1:8080;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

This example assumes the proxy receives client connections directly. It replaces a client-supplied forwarding chain with the connecting address, which avoids accepting an arbitrary identity from a request header. Putting another proxy ahead of it requires a deliberate trusted-proxy configuration.

Nginx buffers upstream responses by default, which can be undesirable for event streams. Disable response buffering on the relevant route when the application requires immediate delivery, and verify the result through the public endpoint. WebSockets also need explicit upgrade handling beyond this basic example.

We would keep Nginx if replacing it meant rebuilding a well-understood cache policy or translating complicated routing behavior. We would not add caching just because the directive exists. A mistaken cache rule can expose private responses or serve stale application state.

Check application behavior before changing the edge

A successful homepage request proves very little about a proxy migration. Your application may depend on a path rewrite that only runs during login, or on an upload limit that ordinary browsing never reaches. Write down the behavior the current edge provides before translating its configuration.

  • Check login redirects and secure cookies through the public HTTPS hostname.
  • Exercise uploads using files representative of your application's normal workload.
  • Open WebSocket connections or event streams and confirm that updates arrive promptly.
  • Compare upstream paths for routes that add or remove a URL prefix.
  • Confirm the application records the expected client address without trusting arbitrary forwarded headers.
  • Inspect error responses and access logs so failures remain diagnosable after the change.

Configure your framework to trust only the actual proxy path. Trusting every sender becomes dangerous if the application port is accidentally exposed later. When a CDN sits in front, review both the CDN-to-proxy trust relationship and the proxy-to-application relationship.

Preserve the old configuration and its service settings before switching public listeners. Caddy and Nginx cannot both bind the same address and port, so plan a controlled handoff with a rollback procedure. A reload within one service and a migration between different services are separate operations.

Validate changes and give Claude Code a bounded task

We use Claude Code for drafting configuration changes and investigating failures, with a narrow scope. Ask it to explain each changed route and produce the exact validation command before applying anything. A shorter Caddyfile can make review easier, but it does not make an unchecked edit safe.

For the Caddy example, save a copy of the working file before editing it. Once your real hostname is configured and the Caddy service is already running, validate the candidate and reload only if validation succeeds. Run validation as the service user so file access resembles the running service.

bash
sudo -u caddy caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile && sudo systemctl reload caddy
Check: Validation reports a valid configuration and the reload exits successfully. This establishes that the service accepted the configuration; it does not establish that public HTTPS or the application works.

For Nginx, require sudo nginx -t to succeed before a service reload. With either server, follow acceptance with an external application check and inspection of recent service errors. If behavior is wrong, restore the saved configuration, validate it, and reload again.

Keep routine agent access away from certificate private keys and unrestricted service administration. We also keep DNS changes separate from proxy edits so a failed check has a smaller set of possible causes. Use these production guardrails for AI agents to define what Claude Code may inspect and which changes require your review.

Put one hostname through the full request path

Start with a noncritical hostname and the application route you actually intend to serve. After replacing app.example.com in these commands, run them from your laptop or another external machine with curl installed. The first request checks the HTTP redirect, and the second requests the application over verified HTTPS.

bash
curl --silent --show-error --output /dev/null --dump-header - http://app.example.com/
curl --fail --silent --show-error --output /dev/null --dump-header - https://app.example.com/
Check: The HTTP response redirects to the expected HTTPS hostname. The HTTPS request completes without a certificate error and returns the response your application expects, rather than a default server page or gateway error.

Open the application in a browser and complete an authenticated action if it has accounts. If it uses a persistent connection, reload the proxy while watching that connection and confirm that the client recovers correctly. Caddy can close existing WebSocket connections during configuration reloads, so ordinary page availability does not prove uninterrupted streaming.

Make that hostname your first operational checkpoint: record the configuration location and the rollback command beside its external health check. Move your next hostname only after the first behaves correctly. If you are retaining Nginx, use the same checkpoint to verify its renewal workflow before spending time on a migration.

FAQ

Is Caddy better than Nginx for a reverse proxy?

For an ordinary application on a new VPS, Caddy is our default because the configuration directly expresses the hostname and upstream. Nginx becomes the better choice when its existing rules or specific modules are part of your application's requirements. Include the effort of understanding and maintaining those rules in your decision.

Does Nginx support automatic HTTPS like Caddy?

Nginx can participate in an automated certificate setup through a separate ACME client or its ACME module. The practical question is which mechanism your installation actually provides and who maintains it. Caddy integrates certificate management into its usual hostname configuration, which removes a separate setup task for a straightforward public application.

Is Caddy faster than Nginx?

There is no useful universal winner for your application. Proxy resource use depends on the request workload and enabled features, while slow upstream responses can dominate the user experience. If capacity becomes a problem, exercise your own routes under representative traffic and inspect resource use before deciding that replacing the proxy will help.

Can a Caddy reverse proxy handle WebSockets?

Yes, Caddy's reverse proxy supports WebSocket connections without a separate upgrade-header configuration for the usual case. You still need to verify application timeouts and reconnection behavior. Pay particular attention to configuration reloads: an application that assumes a socket will remain connected indefinitely needs a recovery path regardless of which proxy you choose.

Should I replace an existing Nginx server with Caddy?

Start by naming the problem you expect the replacement to solve. Repeated certificate-management trouble or configuration that nobody understands can justify a migration. A working Nginx setup with documented ownership is usually worth keeping. If you move, inventory its behavior first and migrate a noncritical hostname before changing the main application's traffic.

Free ebook

Put this guide in the bigger picture

See how this topic connects to the rest of your product. Our free field guide explains apps, infrastructure and AI, with checklists to help you make business decisions.

We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.