Tutorial: convert a nginx conf to caddy config

This guide is a tutorial of how to convert a nginx config to caddy config.

Nginx config only include bare minimal blocks for brevity, without surrounding server blocks, listen, ssl settings etc.

1. Simple reverse proxy

A common use case, we run a http application and expose it to the internet with reverse_proxy.

nginx config

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_pass http://localhost:port;

In caddy, however following is enough

example.com {
    reverse_proxy localhost:port

caddy automatically sets Host, X-Forwarded-For headers for you. As a bonus, caddy can handle websocket this way without additional configuration. Some caddy tutorials list websocket as a separate directive and that’s a caddy v1 thing.

2. Fastcgi

Fastcgi is not http and requires different handling to execute php scripts and serve static files that are usually accompanying.

nginx config

    root /var/www/html;
    location / {
        try_files $uri $uri/ =404;
    location ~ \.php$ {
        include /etc/nginx/fcgi_params;


example.com {
    root * /var/www/html

Because of how php frameworks handles routing, you may have to lookup documentation to change the configuration as need. Some caddy tutorials list fastcgi as a directive and that’s a caddy v1 thing.

3. Tips to convert complex nginx config to caddy config

Because website is never simple, and not every nginx config is straightforward, there’re usually path matching, header matching, static file server, caching, load balancing etc. And different configurations can achieve the same purpose. When migrating to caddy, first break down what original config is doing one by one.

  1. File server and access logging usually goes to the top level of a site block.
  2. If a request matcher is too complex, i.e. matching by header, by request path, by request protocol etc., wrap them as a named matcher and use it.
  3. If a location block requires a different handling, i.e. reverse proxy to different types of backends(http, grpc or fastcgi), serve static file from other directories, wrap it with handle blocks and specify processing logic inside it. (If these different handlers are all reverse_proxy, reverse_proxy backend_path is a simpler way).
  4. Searching this community for similar questions on how to convert nginx config to caddy, someone may have the same problem and have already solved it.
  5. Referring to official caddy documentation or ask directly in this community, some caddy tutorials are just too old to provide useful information.

Caddy is a still evolving web server and we’re happy to hear any feedbacks you guys have!