Removing only one of the Server headers

1. The problem I’m having:

I am using Caddy to terminate SSL, with reverse_proxy. Caddy adds a Server header to the response. But the response from the upstream already has a Server header. Which means I now have two Server headers. I would like to remove just the Caddy Server header.

2. Error messages and/or full log output:

I looks like I can only remove both Server headers at once. Am I missing something?
Or is is perhaps possible to join the two headers so I can use a replace to clean up?

3. Caddy version:

$ caddy version
2.6.2

4. How I installed and ran Caddy:

$ sudo apt-get install caddy

a. System environment:

Ubuntu 24.04 server

b. Command:

$ sudo systemctl start caddy

c. Service/unit/compose file:


d. My complete Caddy config:

{
        http_port 6080
        https_port 6443
        auto_https disable_redirects
        grace_period 7s
        email webmaster@okaphone.nl
}

okaphone.com:6080,
www.okaphone.com:6080,
kassa.okaphone.com:6080,
ntp.okaphone.com:6080,
webcam.okaphone.com:6080,
stats.okaphone.com:6080,
okaphone.com:6443,
www.okaphone.com:6443,
kassa.okaphone.com:6443,
ntp.okaphone.com:6443,
webcam.okaphone.com:6443,
stats.okaphone.com:6443 {
        reverse_proxy proxy.okaphone.com:8080 {
                header_up Host {hostport}
        }       # Varnish
        header -Server
}

svn.okaphone.com:6080 {
        respond Forbidden 403 {
                close
        }
}

svn.okaphone.com:6443 {
        reverse_proxy svn.okaphone.com:7080 {
                header_up Host {hostport}
        }       # Apache
}

# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile

5. Links to relevant resources:

Put header_down -Server into the reverse_proxy block you want to remove the Server header from, as per the documentation.

stats.okaphone.com:6443 {
        reverse_proxy proxy.okaphone.com:8080 {
                header_up Host {hostport}
                header_down -Server
        }       # Varnish
}

Also, consider upgrading Caddy using the official repository.

That removes the wrong header. I would lose the information I need. :frowning:

Maybe Caddy should use a Via header when it is reverse proxying. But as it is, I would be happy if I could just remove the Caddy Server header.

We do, but Debian hasn’t upgraded Caddy in ages. You’ll get that behavior once you use our official repository and upgrade Caddy.

2 Likes

Ah, good. Well, if you advise against using Caddy on Ubuntu because of that, I should perhaps take a look at Nginx to see if that will do the SSL-termination job for me.

It’s not a hobby… What I really need is LTS, much more so than the absolute latest and greatest version of all of the software I’m using. :wink:

1 Like

Maybe I should consider using X-Server in the upstreams. Then I can remove the Server header and will be left with what I need. It’s not pretty but it’s a possibility.

That is if there is no way to remove just the Caddy Server header. Nobody said it yet, but I gather that is the answer: Can’t.

Nobody advised this. We’re telling you use Caddy’s official repository, as listed on the Caddy official documentation, which is linked by @techjedialex. The package provided by Debian/Ubuntu is not always up to date. Ours (official Caddy repository) is always up to date.

That’s false. As I already said, upgrade Caddy to latest and you’ll see it using the Via header while keeping the Server header from upstream.

2 Likes

And another idea:

Is there a placeholder that will give me de value of the Server header from the upstream response? All I could find was {http.response.header.Server"} but that is not the one from the upstream. It just gives me “Caddy”.

I think I could do something if such a placeholder exists.

Can’t guarantee this will work with your old v2.6.2, but give it a try:

example.com {
  tls internal

  reverse_proxy localhost:8080 {
    handle_response {
      header X-Server {rp.header.Server}
      copy_response
    }
  }
  header -Server
}

:8080 {
  header Server "Upstream WebServer"
  respond "upstream" 200
}

Test:

$ curl https://example.com -i
HTTP/2 200 
alt-svc: h3=":443"; ma=2592000
content-type: text/plain; charset=utf-8
date: Wed, 25 Mar 2026 01:12:54 GMT
via: 1.1 Caddy
x-server: Upstream WebServer
content-length: 8

upstream
3 Likes

Also, not sure again how that behaved in v2.6.2, but if you want to hardcode a specific Server header, you can just do this:

example.com {
  tls internal

  reverse_proxy localhost:8080 {
    header_down Server "My Webserver"
  }
}

Test:

$ curl https://example.com -i
HTTP/2 200 
alt-svc: h3=":443"; ma=2592000
content-type: text/plain; charset=utf-8
date: Wed, 25 Mar 2026 01:24:53 GMT
server: My Webserver
via: 1.1 Caddy
content-length: 8

upstream
2 Likes
... {
        reverse_proxy proxy.okaphone.com:8080 {
                header_up Host {hostport}
                header_down -Server
                handle_response {
                        header Server "^Caddy$" "{rp.header.Server}"
                        copy_response
                }
        }       # Varnish
        header Via "Caddy"
}

This works! :star_struck:

There, added the Via for good measure.

To further elaborate, the person that added Caddy to Debian has not at all maintained it since, and never got in contact with us in the first place. We’re extremely annoyed about this, because it causes users like you to get misled to use an old broken version of Caddy which we have no control over. DO NOT use that version, DO use the apt repo in our official docs.

2 Likes

That is indeed a sad state of things… and exactly why I said I should perhaps look at other ways to implement my use case.

Of course I can follow you suggestion. But do I want to? Do I need to? How does that work with regard to LTS? You say you only support the latest version of Caddy. What about security patches, upgrades, handling breaking changes? People use software distributions for a reason. I may not be in a position or have the means or priorities to take care of all that…

Which is why it would be so much more useful if the Caddy was properly maintained in popular software distributions. Maybe this list, which has contact information for the maintainers, is of use:

… while I consider my options, that is. :wink:

Question in this context:

If I follow your recipe will it break my current installation? Will I perhaps have to uninstall and reinstall? Or will an apt-get upgrade just upgrade me to the latest version and maybe only require a few minor tweaks to my Caddyfile?

No, in fact the opposite, it will fix your installation. Using our official installation method is obviously what you should be doing. We do not support the outdated debian package. You will get regular updates via our apt repo, it shadows and replaces the debian package since they share the same name.

We don’t do LTS.

We do not patch old versions, we only release new versions. So you must use the latest to keep up on security patches.

We are careful to avoid breaking changes, but you can watch the release notes on Github for any alerts about that should they happen (they are relatively rare).

Anyway, this thread prompted me to go yell at Debian maintainers about this because they’ve caused us enough grief from complaints like this that are out of our control https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1110530. It’ll probably land on deaf ears though. :roll_eyes:

1 Like

Thanks for answering my question.

Their way of dealing with Caddy may very well have been chosen as a consequence of your choice to only support the latest version. Is what I’m thinking… :innocent:

Anyway, thanks for trying again. I too contacted Canonical about this problem, by the way.

(But at the moment Caddy is smoothly terminating SSL for me.)

And the status quo will have to serve for my own choices in this…

No, there was just no choice made. There’s nobody actually maintaining it. It was just one guy who set it up, and it’s been left as-is since.

The fact is, Debian’s policies regarding packaging Go apps is really messy. They decided they have to package every single Go subdependency as separate deb packages so they can build the final program. That’s obviously ridiculous considering the amount of transient dependencies Caddy happens to have, mostly because packages we depend on for small subsets of their functionality happen to also be full apps of their own right, (like smallstep which is a whole CA toolkit, we only use the library APIs of it, but it pollutes the Go dependency chain due to how Go modules work).

You also need to realize we’re a small team, all of us volunteers with full time jobs, aside from Matt who has his time funded via sponsorships. We don’t have time to maintain multiple release branches, so we only support the latest, unless a sponsor specifically requests a branch is maintained for them for their own technical reasons.

Caddy is constantly improving, it’s really in your best interest to use the latest version via our official installation method, to get security fixes and latest features and optimizations, in also keeping up with integrations with services like Let’s Encrypt.

That is their choice and their way of dealing with Caddy, it seems. :face_blowing_a_kiss:

We don’t have time to maintain multiple release branches, so we only support the latest

That is your choice, which I understand and respect, but which also influences my choices, as I was trying to say.

it’s really in your best interest to use the latest version via our official installation method

That is for me to decide, my choice. :rofl:

#noproblem

I have been thinking about this…

Maybe, with your limited resources, you could still afford to run two branches. One stable and one hot. Where the stable package only gets urgent (security) fixes. And regularly (say anually, perhaps after a bit of a freeze) you merge the current hot branch to this stable branch.

I think offering that may help you in your goal of more adoption outside of the hobby sphere. It would probably also help you when talking to the big(ger) software distributions. Stability is obviously a major consideration for them. :smiling_face_with_sunglasses:

I for one, would also be more inclined to use that than what you are currently offering.

#justasuggestion

Ad some nice release notes to that and this could be a significant step in the direction of world domination… :face_with_peeking_eye:

#mypleasure #dontmentionit

That already exists. The “master” branch is “hot” and releases which happen a couple of times a year are “stable”. I understand this doesn’t match your understanding of what stable may be coming from debian, but it matches my understanding as somebody that doesn’t use debian specifically because it’s way too out of date for me.

4 Likes