Search code examples
djangopostgresqldockerubuntuufw

ufw forbids docker container to connect to postgres


On ubuntu 18.04 with ufw enabled I run docker container which is supposed to connect a django app to a locally installed Postgresql server.

Everything runs perfect when ufw is disabled

docker-compose -f docker-compose.prod.yml run --rm app  sh -c 'python manage.py createsuperuser'

But with enabled ufw I get the following error:

 conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
django.db.utils.OperationalError: could not connect to server: Operation timed out
    Is the server running on host "host.docker.internal" (172.17.0.1) and accepting
    TCP/IP connections on port 5432?

I have following ufw rules

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
Nginx Full                 ALLOW       Anywhere                  
OpenSSH                    ALLOW       Anywhere                  
20/tcp                     ALLOW       Anywhere                  
21/tcp                     ALLOW       Anywhere                  
990/tcp                    ALLOW       Anywhere                  
40000:50000/tcp            ALLOW       Anywhere                  
Nginx Full (v6)            ALLOW       Anywhere (v6)             
OpenSSH (v6)               ALLOW       Anywhere (v6)             
20/tcp (v6)                ALLOW       Anywhere (v6)             
21/tcp (v6)                ALLOW       Anywhere (v6)             
990/tcp (v6)               ALLOW       Anywhere (v6)             
40000:50000/tcp (v6)       ALLOW       Anywhere (v6)  

How to configure ufw properly and let the container connect to Postgres?


Solution

  • Your firewall is blocking the connection from docker container since it originates on another network.

    To fix this you should enable access from that docker network to your Postgres instance (I assume its port 5432).

    So, when you use docker-compose up, a specific docker network is created. You can look it up by using command:

    docker network ls

    When you locate your network use command docker inspect {network name} to get additional information about it. The information you are looking for is the network's gateway. The portion of it should look something like this:

    ...
    "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.18.0.0/16",
                        "Gateway": "172.18.0.1"
                    }
                ]
            },
    ...
    

    The ip you are looking for is in this example 172.18.0.1.

    So now you know from which interface your container is connecting to Postgres and you can enable it in your firewall. Since you don't want to open your firewall for everybody you can use something like this:

    ufw allow in from 172.18.0.0/16

    This will also allow the entire network to access and not just specific IPs. That is a useful option since containers can change IPs when restarted.