Fixing Gitea PostgreSQL Docker Connection Issues | Generated by AI

Home 2026.03

🔧 How I Fixed the Gitea ↔ PostgreSQL Connection

The Error

The database settings are invalid: dial tcp 172.17.0.1:5433: connect: connection timed out

Gitea (running in Docker) couldn’t reach PostgreSQL (running on the host). Three separate problems were blocking it.


Problem 1: PostgreSQL Only Listening on localhost

What happened: PostgreSQL’s default config binds to 127.0.0.1 only. That means it only accepts connections from the host machine itself — not from Docker containers.

How I found it:

sudo ss -tlnp | grep 5433
# Output showed: 127.0.0.1:5433 — only localhost!

The fix:

# Changed in /etc/postgresql/16/main/postgresql.conf:
# listen_addresses = 'localhost'        ← old (commented out default)
listen_addresses = '*'                  ← new (listen on all interfaces)

Now PostgreSQL accepts connections on 0.0.0.0:5433 (all IPs) instead of just 127.0.0.1.

Why it matters: A Docker container has its own network namespace. From inside the container, 127.0.0.1 is the container itself — not the host. So localhost inside Docker ≠ localhost on the host.


Problem 2: Docker Network Mismatch

What happened: Gitea was running on a custom Docker network (gitea_default) with gateway 172.22.0.1, but host.docker.internal was resolving to 172.17.0.1 (the default docker0 bridge).

How I found it:

docker inspect gitea --format ': \n'
# Output: gitea_default: 172.22.0.1

docker exec gitea sh -c "getent hosts host.docker.internal"
# Output: 172.17.0.1  host.docker.internal

Docker Compose creates its own network per project. The host.docker.internal mapping uses the default bridge IP, but traffic from a custom network doesn’t always route cleanly to the default bridge.

The fix: By changing listen_addresses = '*', PostgreSQL now listens on all interfaces — including the one reachable from the custom Docker network. No matter which Docker network connects, as long as traffic reaches port 5433 on the host, PostgreSQL accepts it.


Problem 3: iptables Blocking the Connection

What happened: Even after fixing the above two issues, the connection still timed out. The real blocker was iptables — the Linux firewall was silently dropping packets from Docker to the host on port 5433.

How I found it:

# After fixing listen_addresses, tried again:
docker exec gitea sh -c "timeout 3 bash -c 'echo > /dev/tcp/host.docker.internal/5433'"
# Still FAILED

# Then manually opened the port:
sudo iptables -I INPUT -p tcp --dport 5433 -j ACCEPT
# Tried again → OK!

Docker has its own iptables chains. When a container tries to reach the host, the packet goes through the host’s INPUT chain. If no rule allows it, it gets dropped.

The fix (permanent):

sudo ufw allow from 172.16.0.0/12 to any port 5433 proto tcp comment 'postgresql-docker'
Part Meaning
from 172.16.0.0/12 Only Docker networks (172.16.0.0 – 172.31.255.255)
to any port 5433 PostgreSQL’s port
proto tcp PostgreSQL uses TCP

This is more secure than opening 5433 to the whole internet — only Docker containers can reach it.


The Flow After Fixing

1. Browser → http://192.168.1.36:3000
              ↓
2. Gitea container (172.22.0.x)
   resolves host.docker.internal → 172.17.0.1
              ↓
3. Packet hits host's iptables INPUT chain
   ufw rule: "allow from 172.16.0.0/12 to port 5433" → ACCEPT ✅
              ↓
4. PostgreSQL on 0.0.0.0:5433 receives the connection
   pg_hba.conf: "allow gitea user from 172.16.0.0/12" → AUTHENTICATE ✅
              ↓
5. Gitea connects to DB, install page works 🎉

Summary

Problem Symptom Fix
PostgreSQL only on localhost Container can’t reach host’s loopback listen_addresses = '*'
Custom Docker network ≠ bridge host.docker.internal resolves to wrong gateway Already handled by listen_addresses = '*'
iptables drops Docker → host traffic Connection times out ufw allow from 172.16.0.0/12 to port 5433

Back Donate