Running Caddy alongside an existing web site

1. Caddy version (caddy version):


2. How I run Caddy:

In a docker

a. System environment:

Debian docker compose

c. Service/unit/compose file:

version: '3.3'
        container_name: caddy
            - '/etc/Caddyfile:/etc/caddy/Caddyfile'
            - '/etc/caddy:/root/.local/share/caddy'
        network_mode: host
        restart: unless-stopped
        image: caddy

d. My complete Caddyfile or JSON config:

3. The problem I’m having:

Hello, I’ve been using Caddy on my other server, and wanted to use it on a server that hosts a Wordpress site in order to create a staging Wordpress site inside a docker container. the problem is port 443 is already bound and caddy can’t start.

4. Error messages and/or full log output:

run: loading initial config: loading new config: http app module: start: tcp: listening on :443: listen tcp :443: bind: address already in use

5. What I already tried:

I tried adding the main site to the caddy file, but it still won’t start, is this even possible or do I have to change something in my main site to make this work?

6. Links to relevant resources:

That’s not the correct volume path to use. See the docs on Docker Hub

What you should do is let Caddy have ports 80 and 443, then use Caddy to reverse proxy to your existing site(s).

Caddy needs port 80 and 443 to solve ACME challenges.

Make sure to configure I assume Apache to bind on some different port instead, like 8080 or something like that, to allow for Caddy to use ports 80 and 443, then you can have Caddy proxy requests to your wordpress site, and manage certificates for that site as well.


so if I understood you correctly, these are the correct paths:

      - $PWD/site:/srv
      - caddy_data:/data
      - caddy_config:/config

right? that’s another thing I need to change in the linode guide.

also what could these wrong paths affect? i mean now that i’ll change them what can break?

You were not persisting /data, which meant that you would lose your certificates and keys that Caddy generated if you tore down the container. It’s important to persist that information to a volume to avoid issues. This is explained on Docker Hub.

/srv is just the location we recommend to drop in your static files if you need to serve something. It’s optional, you don’t need it if you’re only using reverse_proxy, or prefer to use a different path for your files in the container.

Thanks for clearing that up, i was wondering why it generated new keys everytime it restarted.

so is $PWD/Caddyfile the correct path instead of /etc?

Also, on an unrelated topic, i tried to update the image today after i got the notification that there’s a new version, but when i pulled i just got the same image, do i need to wait for the new one to propagate?

So I’ve tried this, changed my apache port to something else, and set that something else in caddy, now I’ve gone over the whole caddyfile documentation and it lacks a lot of reverse proxy examples.

anyway, I have to revert it to a snapshot I created before changing everything, but here’s my caddy file: {
  encode gzip
 # Notifications redirected to the websockets server
  reverse_proxy localhost:8081
  reverse_proxy https://localhost:444
  } {
  encode gzip
 # Notifications redirected to the websockets server

so yeah, sorry if I missed anything but I’ve looked for nearly an hour, and tried a few configs. i always got “too many redirects” and unreachable on the docker WordPress.

i also tried to curl them from inside the server, got a webserver response on the apache port, and something else on the docker. now the docker might be the fact it could not connect to the database docker, but the apache is my production server and I can’t have it down for so long.

Depends where you want to have your Caddyfile on your host machine. Up to you, really. But the example given has you place your Caddyfile beside your docker-compose.yml. You can do that if it’s convenient for you. Or don’t. That part isn’t so important. The important part is that /data is persisted.

I’m unclear what you mean. What are you seeing? Copy-paste your terminal logs.

So I think what you’re missing is that you’re not using request matchers to tell Caddy when to use one proxy vs the other.

There’s actually an example in the docs on how to match websocket requests:

@websockets {
	header Connection *Upgrade*
	header Upgrade    websocket
reverse_proxy @websockets localhost:8081

Basically this is looking for specific headers in the request, and if the request has those, then @websockets will match it.

The important part is that if it does not match, then that reverse_proxy will not run, and it will fall through to the next reverse_proxy with a less-specific matcher (e.g. one without a matcher, which means match all requests).

The other issue is that you’re using https:// here. If you proxy over HTTPS, then you need to make sure Caddy trusts the certificate your upstream is serving.

I’d recommend just proxying over HTTP instead. There’s no real benefit to proxying over HTTPS to a service running on the same machine, it just adds overhead.

I’d also recommend not using low ports for services only serving locally. Use something like 8888 instead of 444 for example. Low ports (under 1024) require higher permissions in Linux to use since they’re usually reserved to run by trusted system services.

1 Like

got that, thanks.

I mean I do a docker pull caddy, and it says the image is already up to date, but the digest is not the newest one and the date of the image is 6 weeks ago. so it’s not downloading the new image.

i thought putting the host outside the curly brackets meant that if it’s this host go to this address with this port i.e. the first reverse proxy line. but if it’s another subdomain go the first line in that pair of curly brackets. i think this is where I misunderstood because I have 3 sites running well in dockers with the exact method in caddy.

i mean like this:{
reverse_proxy xxxxx
reverse_proxy xxxxx

and so on.

so another misunderstanding, I thought I needed to specify a reverse proxy for traffic that is coming through HTTPS. I guess I can remove those?

If you run docker run --rm -it caddy caddy version and see v2.4.3, then you have the latest. The one from 6 weeks ago is the latest version. See the release notes on github.

You had two reverse_proxy lines inside of one site block. reverse_proxy is an HTTP handler directive. When you have two, without using request matchers, it’s ambiguous which one should be executed when.

You’re correct that Caddy matches first based on the hostname of the request, and that’s how it “chooses” which site block to use, but then after that, you still need to tell it how to choose which reverse_proxy.

Caddy will terminate HTTPS. Communications from Caddy to your other services don’t need to be encrypted, because they happen all on the same machine, privately.

1 Like

so I should change my alert to GitHub instead of docker hub? see this link that says the last push was 17 hours ago. Docker Hub

so let’s see if I got this straight, I only need 1 line of reverse proxy and it does not matter if say a docker has many ports that use general traffic, I just specify one?
like for example, the main site which is apache, I changed the port from 80 to 8081 and the SSL port from 443 to 444, I don’t need that? I can only specify the 8081 and caddy will know to route HTTPS to the end-user?

did I understand that correctly?

Docker Hub has bots that continually rebuild images based on certain rules. That doesn’t mean the image actually changed.

I do recommend watching the Caddy repo on github to be alerted for releases. That way you get to see the release notes as well.

Note that the new versions of Caddy don’t land on Docker Hub right away, it requires a few humans in a row to trigger things for the build to end up on Docker Hub.

If you need to proxy websocket requests to one server, and HTTP requests to another server, then you do need two reverse_proxy lines. But you need to tell Caddy which one to use, when.

You don’t need Apache to serve HTTPS anymore, only HTTP. So you can simply proxy to 8081, if that’s your HTTP port for Apache.

Maybe the comment you had in your Caddyfile was unclear. It seemed like you had two reverse_proxy because one was for websocket requests, and the other was for everything else. Was that untrue? I was reading this:

1 Like

got it, will change it to the github repo. thanks.

Yep, that’s where I misunderstood. I forgot that caddy was a man in the middle that I deal only with caddy from the outside.

to tell you the truth, it’s a copy-paste from my other server, that comment just got transferred in the testing haze. it means nothing.

so thank you for all your answers I might try again tomorrow and let you know if this solved everything.


Ok, so here’s my update:

  1. I tested editing the caddy file on my other server first, changing the caddy docker to include the settings you suggested so it would retain data. that worked after a while, I had to add network_mode: host and remove the ports from the compose file because I have a service that uses different ports.

  2. i tried doing the same thing on my WP server, I first made sure caddy would run, then made the caddy file work. but then I had to change the apache listening port, and that’s where I hit a lot of bumps in the road.

a. I first got an Nginx webpage on the main site while the staging site displayed the “error connecting to database” WordPress does whenever there’s a problem with accessing the database. so I had to change another file in /etc/apache2/sites-enabled to have wordpress listen on the new ports. which leads me to b.

b. once wordpress was listening on the ports the website loaded, but without the theme and just basic text. I’ve seen this happen when there’s a problem accessing the database.
would caddy need to redirect that traffic as well? i thought that’s something that would be handled on the same server and does not need a caddy config for.

So that’s where I’m at, 80% there, but had to revert the ports in order for the site to function until I find the solution.

Were you previously accessing your WP site unencrypted (over http) and now you’re accessing the site behind a reverse proxy? If so, this is a known WP issue. There are two solutions. Refer to New Page: How to move WordPress site from HTTP to HTTPS · Issue #333 · WordPress/HelpHub · GitHub. This Caddy forum thread Help HTTPS to bitnami wordpress (mixed content error, need to force-rewrite http to https) will lead you to the first solution suggested in issue #333.

1 Like

nope. was https before, so nothing has changed in that regard. it’s just some traffic isn’t reaching the database.

The text only with no theme/images looks suspiciously like the well-known mixed content WP issue.

i’ve had that before, when i migrated my site to the new hosting, the solution then was the database access in the wp-config. so seeing as that did not change, i’m guessing i’m missing some sort of traffic funneling or something.

OK, I had some time today to try this again, however, this time around, I could not even get the website to load.

here are my steps so far. since it’s running an apache server, I change the ports in nano /etc/apache2/ports.conf then I change the ports in /etc/apache2/sites-enabled/wordpress.conf and wordpress-le-ssl.conf then I run systemctl restart apache2 and start caddy.

what I got today was either too many redirects, you’re trying to talk SSL over HTTP, or simply site not found. am I missing a step in putting this site behind caddy?

just for fun, the staging site that was built in a docker specifically for caddy works in the sense that I get an error establishing a connection to the database error which means it actually reaches it.

any clue?

You’ll need to be more specific. Post the actual errors you get, your configs, etc. Otherwise, we have to make assumptions and guess, and that’s a waste of time for both of us.

ok which files do you need me to post exactly?