Alex's website

Docker and Firewall

I was today years old when I learned that running a Docker container may bypass the firewall rules you have set.

Granted, I'm a complete noob when it comes to self-hosting or Linux, so it does make sense. But still.

Usually, whenever I set up a new VPS, I always follow some sort of guide to set up a non-root account and some basic firewall rules. You know, for security reasons and whatnot. I've never run and managed a Docker container myself. Always some sort of cloud services like GCP Cloud Run or my favorite fly.io.

In an attempt to "go back to the basics", I've gone and rented a new VPS and hosted this site on it. The goal is to learn things I would never run into had I gone with a cloud provider. I didn't know I would run into them so soon.

So, here's the setup. I have a fresh Debian machine that I closed every port but 22 for SSH, 80 for HTTP, and 443 for HTTPS. Requests to port 80 and 443 are routed to Caddy, a reverse proxy, before getting routed to some port running locally. This website is powered by Pocketbase, so I used its default 8090 port. Pretty standard, I'd think.

This is the simplified Docker Compose file for the site:

services:
  app:
    image: alexluong/alexluong.com
    restart: unless-stopped
    ports:
      - "8090:8090"

In my server, I'd run docker-compose up to start the container, and off we go.

Earlier today, as I was hanging out on the internet, as one does, I came across someone sharing that their VPS was "hacked" through a Docker container running in a port that's supposedly blocked by Firewall. Apparently, it's a whole thing. I'm not going to (and not able to) dive much deeper into it. You can learn more about it here.

In my Docker Compose above, the line "ports: - 8090:8090" is to map the host 8090 port to the container's 8090 port. For the host, I've always thought it's localhost, because when I visit localhost:8090, it works. I was mistaken. Without specifying the hostname or IP address, it defaults to 0.0.0.0. And apparently, there's a difference between localhost (or 127.0.0.1) and 0.0.0.0.

127.0.0.1 is the local network. "localhost" is the usual hostname for it. So when you visit localhost, you're going to 127.0.0.1, which is the local network of your computer.

0.0.0.0 seems to be more. If something is listening on 0.0.0.0:8090, you can visit it via localhost:8090 or 127.0.0.1:8090. But anyone having access to your IP can also visit it via YOUR_IP:8090. Usually, you have firewall rules to prevent this, but in this case, Docker has bypassed it and unwantedly exposes your computer to the public.

Here's my updated configuration:

services:
  app:
    image: alexluong/alexluong.com
    restart: unless-stopped
    ports:
      - "127.0.0.1:8090:8090"

and this seems to have fixed the issue. We're now safe and secure, as far as I can tell.

This has been a fascinating experience, and I trust this is only the first of many mistakes I'll make as I continue my self-hosting journey. Here's to many more mistakes to come.