Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 7 min read

Caddy Web Server Tutorial: Architecture, Docker & Production Guide

Originally published on Naveed Ahmed's Tech Blog. If you've worked with Nginx or Apache, you've probably spent some time configuring virtual hosts, setting up SSL certificates, troubleshooting reverse proxy rules, or fi

Originally published on Naveed Ahmed's Tech Blog.

If you've worked with Nginx or Apache, you've probably spent some time configuring virtual hosts, setting up SSL certificates, troubleshooting reverse proxy rules, or fixing certificate renewal issues.

These are normal parts of managing web infrastructure, but they can become repetitive, especially when you're responsible for multiple services.

That's where Caddy caught my attention.

Caddy is an open-source web server and reverse proxy written in Go. One of its biggest advantages is that it handles HTTPS automatically, including obtaining and renewing TLS certificates.

You can also configure a reverse proxy with just a few lines.

But how does Caddy actually work? Is it secure enough for production? And should you consider it instead of Nginx or Apache?

I put together a detailed guide to explore these questions.

Here's a practical overview of what I covered.

1. What Is Caddy, and Why Should DevOps Engineers Care?

Caddy is a modern web server that can serve websites, handle HTTPS connections, and route incoming requests to backend applications.

It supports many features you'd expect from a production web server:

  • Automatic HTTPS and TLS certificate renewal
  • Reverse proxy and load balancing
  • HTTP/2 and HTTP/3 support
  • Simple Caddyfile configuration
  • Dynamic configuration through a REST API
  • Docker and container-based deployments

What makes Caddy interesting isn't that these features are impossible to implement with other web servers.

It's that several of them work with very little configuration.

For example, here's a basic reverse proxy configuration:

example.com {
    reverse_proxy localhost:3000
}

That's enough to tell Caddy to forward requests to an application listening on port 3000.

With a public domain, correct DNS records, and the required network access, Caddy can also provision and manage HTTPS certificates automatically.

For small applications and containerized services, this can save quite a bit of setup time.

2. Caddy vs. Nginx vs. Apache: Which One Makes Sense?

Nginx and Apache have been around for years, and there's a reason they're still widely used.

Both are mature, flexible, and proven in production environments.

Caddy takes a slightly different approach, with more emphasis on sensible defaults and simplifying common configuration tasks.

Here's how I look at the three:

Feature Caddy Nginx Apache
Automatic HTTPS Built-in Usually requires additional setup Usually requires additional setup
Configuration Simple Caddyfile Directive-based Directive-based
Reverse proxy Built-in Built-in Available through modules
HTTP/3 Supported Supported in compatible builds Depends on implementation
Dynamic configuration REST API Depends on edition and tooling Typically file-based
Common use case Simple HTTPS and reverse proxy setups High-performance web serving and proxying Flexible web hosting

I wouldn't say Caddy is automatically better than Nginx or Apache.

If you already have a well-managed Nginx environment, there's no reason to migrate just for the sake of using something newer.

But if you're starting a new project and want HTTPS and reverse proxy configuration to be straightforward, Caddy is worth considering.

The best choice still depends on your workload, operational requirements, and existing infrastructure.

3. How Secure Is Caddy?

Security is one of the more interesting parts of Caddy's architecture.

Because it's written in Go, Caddy benefits from memory safety features that help prevent certain classes of memory-related vulnerabilities common in manually managed memory environments.

However, that doesn't mean Caddy is free from vulnerabilities.

Like any web server, it still needs proper configuration, timely security updates, and operational monitoring.

For production environments, I'd pay particular attention to:

  • Running the service with minimal privileges
  • Restricting access to the administration API
  • Keeping Caddy and its modules updated
  • Protecting TLS certificate storage
  • Limiting unnecessary network exposure
  • Monitoring logs and reverse proxy errors

One important detail is Caddy's administration API, which normally listens on a local interface.

It's useful for dynamic configuration, but you shouldn't expose it publicly without appropriate security controls.

Automatic HTTPS is a helpful feature, but it doesn't replace good server security practices.

4. Installing Caddy on Ubuntu or Debian

Getting started is relatively simple.

For Ubuntu and Debian systems, Caddy provides an official package repository.

First, install the required packages:

sudo apt install -y \
  debian-keyring \
  debian-archive-keyring \
  apt-transport-https \
  curl \
  gnupg

Add the official repository signing key:

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

Add the repository:

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

Make the repository files readable:

sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg

sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list

Install Caddy:

sudo apt update
sudo apt install -y caddy

Verify the installation:

caddy version
sudo systemctl status caddy --no-pager

The official package installs Caddy as a systemd service, making it easier to manage on Linux servers.

5. Using Caddy as a Reverse Proxy

Let's say you're running a Node.js application on port 3000.

Instead of exposing that application directly to the internet, you can put Caddy in front of it.

A simple Caddyfile looks like this:

app.example.com {
    encode zstd gzip

    reverse_proxy 127.0.0.1:3000
}

In this example, Caddy:

  • Receives requests for app.example.com
  • Handles HTTPS automatically when the domain and network are configured correctly
  • Enables response compression
  • Forwards requests to the Node.js application

Before applying changes, validate the configuration:

sudo caddy validate --config /etc/caddy/Caddyfile

Then reload Caddy:

sudo systemctl reload caddy

This is one of my favorite parts of Caddy.

A common reverse proxy setup doesn't need a large configuration file, and you don't have to manage a separate certificate renewal workflow for typical publicly accessible domains.

6. Running Caddy with Docker

If you use Docker regularly, Caddy can also run as a container.

For example, you can start it with:

docker run -d \
  --name caddy \
  -p 80:80 \
  -p 443:443 \
  -p 443:443/udp \
  -v "$PWD/Caddyfile:/etc/caddy/Caddyfile:ro" \
  -v caddy_data:/data \
  -v caddy_config:/config \
  caddy:2

This assumes you've created a Caddyfile in your current directory.

The named volumes are important because Caddy needs persistent storage for certificate data and configuration state.

For a real deployment, I'd recommend using Docker Compose and placing Caddy on the same Docker network as the backend services.

That way, you can route requests using container service names rather than exposing every application's ports publicly.

For example:

app.example.com {
    reverse_proxy app:3000
}

Here, app would be the name of a backend service reachable through the shared Docker network.

It's a clean approach for applications that need HTTPS without a complicated reverse proxy setup.

7. Would I Use Caddy in Production?

Yes, I'd consider it, particularly for environments where keeping the web server simple is a priority.

Some good use cases include:

  • Small and medium-sized web applications
  • Containerized services
  • Internal applications and developer platforms
  • Reverse proxies for APIs
  • Self-hosted tools and dashboards

But there are still things I'd check before deploying it:

  1. Certificate storage: Make sure certificate data survives container restarts and redeployments.
  2. Networking: Confirm DNS records, firewall rules, and ports 80 and 443 are configured correctly.
  3. Monitoring: Collect access logs, error logs, and relevant operational metrics.
  4. Security: Keep the admin API restricted and run the service with appropriate permissions.
  5. Configuration management: Store the Caddyfile in version control and validate changes before deployment.

And, as with any infrastructure component, I'd test it against the actual application's requirements rather than choosing it based on benchmark numbers alone.

πŸ“– Want to Go Deeper?

This post covers the basics, but there's more to consider when running Caddy in production.

I wrote a longer, hands-on guide that explores:

  • Caddy's architecture and request handling
  • Caddy vs. Nginx vs. Apache
  • Security considerations and hardening
  • Installing Caddy across different environments
  • Docker deployment and reverse proxy configuration
  • Automatic HTTPS and certificate management
  • Production configuration and troubleshooting

If you're evaluating Caddy for your next project, the complete tutorial should help you get started.

πŸ‘‰ Read the Complete Caddy Web Server Tutorial: Architecture, Docker & Production Guide

Final Thoughts

One thing I've learned while working with infrastructure is that more configuration doesn't necessarily mean a better setup.

Sometimes, reducing the number of moving parts makes systems easier to maintain.

That's what makes Caddy interesting to me.

It doesn't replace every use case for Nginx or Apache, but it offers a practical alternative, especially when automated HTTPS and simple reverse proxy configurations are priorities.

I'd be interested to hear how others are using it.

Have you tried Caddy in production? Do you prefer it over Nginx, Apache, or Traefik?

Share your experience in the comments. I'd love to hear what worked, what didn't, and whether you'd recommend it.

About the Author

I'm Naveed Ahmed, a Lead DevOps & Platform Architect. I write about DevOps, Linux, cloud infrastructure, containers, Kubernetes, and production engineering.

You can find more of my work here:

Thanks for reading, and happy building!

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.