Reverse Proxy to host from Docker using Caddy
This is mostly written for future me so I can find out why I did this and what for.
I just installed Ghost 6.0 on my VPS to use as my website and to set it up I used the future recommended way of doing so, Docker. The VPS was brand new, so I didn't think more about that that the docker container would take ownership of port 80 and 443 to use for the Ghost website. I did hit some issues with file hosting in Ghost, I wanted to just upload some files and link to them, and apparently that is not the Ghost way. I thought, no biggie, I will just start an nginx or Caddy on the server, set up a file server I can use to store the files in and then link to them from Ghost.
That didn't work of course since the Docker container was using the standard ports. I tried going and modifying the compose.yml
file and change the ports that Caddy uses in the docker and then set a reverse proxy in front of it. That also failed, probably something simple missing about certificates or whatnot. I also didn't like this method since the compose.yml
file is in git and I would have to modify it again every time a new update of Ghost came out.
What I can modify is the .env
file and the caddy/Caddyfile
. I searched a bit more and found a Reddit thread saying that you can easily proxy out of a Docker container to the host, you just need to use the host actual IP address instead of localhost. The only things required is a webserver running on the host on a non standard port and modifying the caddy/Caddyfile
in the /opt/ghost
folder. Both of which I can do without having to maintain a file that reverts every time a new update comes out.
The setup
Install Caddy on the host, set up the Caddyfile to a custom port that stays on HTTP, for example 8080.
:8080 {
root * /opt/files
file_server
}
From the /opt/ghost
folder edit the caddy/Caddyfile
. Add a new site with the subdomain–or any domain really–you want and reverse proxy it to the host using the host IP address and the port selected in the host Caddyfile. Add http://
to force regular HTTP. Since we are running everything inside the host, there is no need for a certificate.
subdomain.{$DOMAIN} {
import snippets/Logging
handle {
reverse_proxy http://HOST_IP_ADDRESS:8080
}
encode gzip
import snippets/SecurityHeaders
}
I based it on the admin block and removed what I don't need but kept the logging and security headers since that feels prudent. Maybe a mistake, who knows. I also feel like it is better to put all the headers on the public facing server, not sure what gets proxied and what does not.
You can of course put whatever domain you want, it does not have to be a subdomain of {$DOMAIN}, just has to point to the server.
Start caddy
on the host, I am using Ubuntu so we type sudo service caddy start
. Then rebuild the Caddy container on the ghost docker install using docker compose up -d --force-recreate caddy
from inside the /opt/ghost
folder.
Now you have a Ghost 6 install running in Docker hogging both port 80 and 443 and still able to run other websites outside the Docker container on the host.
Hurrah!