How to connect to an external Postgres database from a Docker container

You would think something as simple as connecting to a database on the localhost would be a simple task in Docker. Unfortunately, accessing resources the local machine requires some special settings because of the obfuscation caused by Docker's virtual networking. To access the Postgres database on my local machine, I had to route around localhost and connect to it via the machine's local IP address. The local IP address I pass in using an environment variable in the docker-compose file like this:

version: '3'
services:
  web:
    container_name: myapplication
    build: .
    command: bundle exec rails s -p 3000
    environment:
      - DATABASE_URL=postgres://postgres:postgres@localhost:5432/myapplication
    extra_hosts:
      - localhost:${LOCAL_IP}
    ports:
      - 3030:3000
    tty: true

In my .env file I populated LOCAL_IP with my local IP address

LOCAL_IP=192.168.1.143

I had to make the following change to the listen_addresses part of my postgresql.conf file in the Postgres data directory: This enabled Postgres to bind to and listen in on connections coming through the local IP address.

#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------

# - Connection Settings -

# what IP address(es) to listen on;
listen_addresses = 'localhost,192.168.1.143'
                                        # comma-separated list of addresses;
                                        # defaults to 'localhost'; use '*' for all
                                        # (change requires restart)

The above setting worked on my local Mac, but for my Ubuntu server, I had to implement the change using the ALTER SYSTEM command from within Postgres:

postgres-# ALTER SYSTEM SET listen_addresses='localhost,172.0.30.143'
ALTER SYSTEM
postgres-# \q

$ sudo service postgresql restart

$ netstat -ntl
  Active Internet connections (only servers)
  Proto Recv-Q Send-Q Local Address           Foreign Address         State      
  tcp        0      0 172.0.30.143:5432        0.0.0.0:*               LISTEN   <- it's listening on the correct IP now   
  tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN     
  tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
  tcp6       0      0 :::3030                 :::*                    LISTEN     
  tcp6       0      0 :::22                   :::*                    LISTEN   

I also had to add the following line to pg_hba.conf

host    all             all             192.168.1.143/32        trust

In case you don't know the Postgres data directory, log into psql and:

# show data_directory;

        data_directory        
------------------------------
 /var/lib/postgresql/9.5/main
(1 row)

Gotcha

On my Ubuntu configuration, I had trobule getting the pghba.conf to work. That's because I created and edited the file in the data directory. I found out that the real location of the pghba.conf file was:

postgres-# SHOW hba_file;

               hba_file               
--------------------------------------
 /etc/postgresql/9.5/main/pg_hba.conf

UPDATE 2/24/19

I recently found a simpler method for doing this by changing the networking settings on the Docker network. Please see my new article from February of 2019.