Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

What I really like about Caddy is their better syntax. I actually use nginx (via nginx proxy manager) and Traefik but recently I did one project with Caddy and found it very nice. I might get the time to change my selfhosted setup to use Caddy in the future but probably will go with something like pangolin [1] because it provides alternative to cloudflare tunnels too.

[1] https://github.com/fosrl/pangolin





I agree. That, and the sane defaults are almost always nearly perfect for me. Here is the entire configuration for a TLS-enabled HTTP/{1.1,2,3} static server:

  something.example.com {
    root * /var/www/something.example.com
    file_server
  }
That's the whole thing. Here's the setup of a WordPress site with all the above, plus PHP, plus compression:

  php.example.com {
    root * /var/www/wordpress
    encode
    php_fastcgi unix//run/php/php-version-fpm.sock
    file_server
  }
You can tune and tweak all the million other options too, of course, but you don't have to for most common use cases. It Just Works more than any similarly complex server I've ever been responsible for.

I find the documentation for the syntax to be a bit lacking if you want to do anything that isn't very basic and how they want you to do it. For example, I want to use a wildcard certificate for my internal services to hide service names from certificate transparency logs, and I can't get the syntax working. Chatgpt and gemini also couldn't.

This here is how it's done, where you have a wildcard dns entry for subdomains of secret.domain.com.

{ acme_dns cloudflare oWN-HR__kxRoDhrixaQbI6M0uwS4bfXub4g4xia2 debug }

*.secret.domain.com {

        @sso host sso.secret.domain.com
        handle @sso {
                reverse_proxy 192.168.200.4:9000
        }

        @adguard host adguard.secret.domain.com
        handle @adguard {
                reverse_proxy 192.168.200.4:9000
        }


        @forge host     forge.secret.domain.com
        handle @forge {
                reverse_proxy http://forgejo:3000
        }

        # respond to whatever doesn't match
        handle {
                respond "Wildcard subdomain does not have a web configuration!"
        }

        handle_errors {
                respond "Error {err.status_code} {err.status_text}"
        }
}

Thank you, I will try that later today.

This integration doesn’t support the dns-01 challenge. So wildcard certs are out of the question at this point.

PS. Oh, this subthread is about Caddy, not Nginx. Nevermind my comment then!

For wildcards you need a Caddy build that includes the dns plugin for your specific provider. There's a tool called xcaddy that helps with that. It's still kinda annoying because now you need to manage the binary for yourself but when I tried it with Hetzner it worked fine.

In case it helps someone else, this is what I do:

    FROM caddy:2-builder AS builder

    RUN xcaddy build \
        --with github.com/caddy-dns/cloudflare \
        --with github.com/greenpau/caddy-security

    FROM caddy:2

    COPY --from=builder /usr/bin/caddy /usr/bin/caddy

    COPY Caddyfile /etc/caddy/Caddyfile
Then just build & run it via docker compose

Is this safe for WordPress though? Every time I look at switching from nginx to Caddy where I have WordPress hosted, I get into the weeds trying to figure out if I need to block certain paths in `wp-includes` and `wp-admin` etc.

For example, from a discussion on the Caddy forum https://caddy.community/t/using-caddy-to-harden-wordpress/13...:

  (harden-wordpress) {
      @harden-wordpress expression `(
      !{path}.matches("/wp-includes/ms-files.php$")
          && ({path}.matches("(?i)/wp-includes/.*\\.php")
              || {path}.matches("(?i)/wp-admin/includes/.*\\.php")
              || {path}.matches("(?i)/wp-content/uploads/.*\\.php")
      )
      )`
      respond @harden-wordpress "Access denied" 403
  }

Caddy does have some bizarre limitations I've run into, particularly logging with different permissions when it writes the file, so other processes like promtail can read the logs. With Caddy you cannot change them, it always writes with very restrictive permissions.

I find their docs also really hard to deal with, trying to figure out something that would be super simple on Nginx can be really difficult on Caddy, if it's outside the scope of 'normal stuff'

The other thing I really don't like is if you install via a package manager to get automated updates, you don't get any of the plugins. If you want plugins you have to build it yourself or use their build service, and you don't get automatic updates.


Actually, you can set the permissions for log files now. See https://caddyserver.com/docs/caddyfile/directives/log#file

Oh good to know!

Do you know if Caddy can self update or if is there some other easy method? Manually doing it to get the cloudflare plugin is a pain.


No, you have to build Caddy with plugins. We provide xcaddy to make it easy. Sign up for notifications on github for releases, and just write yourself a tiny bash script to build the binary with xcaddy, and restart the service. You could potentially do a thing where you hook into apt to trigger your script after Caddy's deb package version changes, idk. But it's up to you to handle.

I am wondering why you said "no" to the self update thing.

https://caddyserver.com/docs/command-line#caddy-upgrade


Because that's not automated, it's a manual command and uses caddyserver.com resources (relatively low powered cloud VMs) with no uptime guarantees. It _should not_ be used in automation scenarios, only for quick manual personal use scenarios.

Is there a way to point it somewhere else to get the binary?

I use Caddy as my main reverse proxy into containers with CloudFlare based DNS let’s encrypt. The syntax is intuitive and just works. I’ve used Traefik in the past with Kubernetes and while powerful the setup and grok ability has quite a bit steeper learning curve.

You can have the binary self update with currently included plugins. I think the command line help says it's beta but has always worked fine for me.

I'll give that a try!

Not only that but Nginx how the configuration is split up into all the separate modules is a lot of extra complexity that Caddy avoids by having a single coherent way of configuring its features.

I checked out pangolin too recently but then I realized that I already have Authentik and using its embedded (go based) proxy I don't really need pangolin.



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: