April 21, 2025
Now that I had something to host (Grafana with metrics for my server), I wanted to have
a real web address where anyone could access it. I looked at a few different web domain
lease platforms, but ultimately recognized Cloudflare as the best choice because of
their great offering of services for DNS routing as well as the wide array of
protections for DOS attacks and similar. I purchased jamesmassucco.com
for
$20/yr.
Before allowing traffic to route to my server, I wanted to make sure I understood the security implications, and wanted to ensure that I did everything I could to keep it secure and not put my home network at risk of hacking. I found a great Reddit comment with a lot of the details I needed. The basic steps were:
- Tell Cloudflare to route traffic to your website to your public home IP address
- Tell Cloudflare to proxy your IP address, so that anyone accessing your site doesn't see your actual home IP address
- Tell your server to ONLY accept traffic from Cloudlfare IP addresses
To accomplish points 1 and 2, I configured them via Cloudflare's website. I also realized that my home IP address could change, so I added cloudflare-ddns to my setup - this tool automatically checks your public IP address on a regular cadence and then uses a Cloudlfare API token you provide it to tell Cloudflare your new IP address if it has changed.
To accomplish point 3, I needed a reverse proxy. A reverse proxy is a lot like a router,
in that it directs traffic in both directions based on specific allowed/known routes. A
reverse proxy can be configured to receive all the traffic hitting your server, and then
direct (or block) that traffic to internal services (e.g. Grafana, your website, etc.).
I had heard of nginx
before but decided that traefik
seemed
simpler and better suited for my basic use case. With the help of ChatGPT (yes, I get a
lot of help from ChatGPT), I set up a basic docker-compose for traefik
and
told it to only accept traffic from the Cloudflare IP addresses. Since I wanted to be
extra, I also wrote a script that would read the Cloudflare IP addresses using
curl
and then write them to an .env
file used by
traefik
so that if they ever change (which they almost never do), I could
easily update them. Automation for the sake of automation? Probably.
Once I had traefik
set up, I added labels to the docker-compose entry for
Grafana that enabled it as a routable service for traefik
and then
registered traefik
routers for http
and
https
traffic to Grafana. I originally only did https
, but
couldn't get that to work and during debug found that if I added an
http
router as well, it would work... I didn't figure out yet why that's
required, so for now I just left it in. I registered a sub-domain
(grafana.jamesmassucco.com
) in Cloudflare and used that as the router
source for Grafana traffic, and boom -
grafana.jamesmassucco.com was live!
Note on Docker Deployments
At this point, I decided I had too much going on to just have a single
docker-compose.yml
file, so I decided to a bit of housekeeping
organization. I setup a networking/
directory for traefik
and
cloudflare-ddns
, and a monitoring/
directory for Grafana and
Prometheus. Each directory got a separate docker-compose.yml
file and it's
own start.sh
script. The start script is really a "restart" script, because
it does the following things:
- Change to current director (
cd "$(dirname "$0")"
) - Shut down containers (
sudo docker compose down
) -
Update container images from the docker repo (
sudo docker compose pull
) - Start up containers (
sudo docker compose up -d
)
The docker compose
command only looks at containers managed by the local
docker-compose.yml
file, so by having separate
start.sh
scripts in each directory, I can separately restart the services
relevant to that aspect of the server. I also set up a top-level
start_all.sh
that just calls each of the start.sh
scripts from
the subdirectories, so I can easily redeploy all of the services if needed.
Next up is a deeper dive into security to make triple sure I'm doing everything I can to prevent getting hacked!