Skip to main content

Step 4

Step 4 — SSH tunnels + loopback binding

4 views

Table of contents

The fewer ports your server exposes, the better. 127.0.0.1 binding + SSH tunnels is the standard answer.

The problem — 0.0.0.0 binding

postgres:
  ports:
    - "5432:5432"   # exposed to the entire internet

Bots will hammer port 5432 for credentials 24/7.

The fix — loopback binding

postgres:
  ports:
    - "127.0.0.1:5432:5432"   # only the server itself

External cannot reach it.

Reach it through SSH tunnel

ssh -L 5433:127.0.0.1:5432 user@my-server.com

Your laptop's localhost:5433 → SSH tunnel → server's 127.0.0.1:5432. Bots can't follow without your SSH key.

psql -h localhost -p 5433 -U user -d myapp

autossh for persistence

autossh -f -N -L 5433:127.0.0.1:5432 user@my-server.com

-f background, -N no shell.

Which ports stay open

Port Public?
22 (SSH, key-only)
80, 443 (Caddy)
5432 (PostgreSQL) ❌ — loopback
6379 (Redis) ❌ — loopback
3000+ (apps) ❌ — Caddy proxies

Only three ports public.

ufw firewall

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw default deny incoming
sudo ufw enable

Try it

Spin up an EC2 free instance, apply the rules above, and nmap your-ip. Only three ports should appear.

Going deeper

Next

Step 5 — AWS essentials.