Search code examples
dockerdocker-composedocker-network

I defined a static IP in the docker compose file but I can only access it on 0.0.0.0


I'm creating a docker-compose file to be able to access different containers over an IP on my machine. My Docker compose file is the following:

version: '3.7'

services:
  apache-php8:
    build: ./apache-php8
    volumes:
     - ../webphp8:/var/www/html/web
    ports:
     - 80:80    
    networks:
      web_net:
        ipv4_address: 192.168.100.4

  mysql:
    image: mysql:5.7    
    restart: always
    volumes:
      - ../data:/var/lib/mysql
    ports:
     - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: test
      MYSQL_USER: test
      MYSQL_PASSWORD: test
    networks:
      web_net:
        ipv4_address: 192.168.100.3

networks:
  web_net:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"
    ipam:
      driver: default
      config:
      - subnet: 192.168.100.0/24
        gateway: 192.168.100.1

I'd expect being able to acces the code on the machine on the 192.168.100.4, as that is the IP that I defined for the server, however, I only access to it in the 0.0.0.0 IP. I'm in an Ubuntu host machine, if that matters.

Do you know why is that, and what I have to do to change it to access the server on 192.168.100.4?

Answer to "Why are you doing it?": I want to be able to develop with two different versions of PHP in the same machine, and access them with two different urls: http://app1.webserver.es and http://app2.webserver.es. I also want a connection to the database that is accessible locally and for the webservers.


Solution

  • The solution for the problem has been changing the approach: instead of using IPs that expose the network, go for a Nginx reverse proxy that manages the incoming traffic from the host to the containers.

    I published the code on this repository: https://github.com/Chocofede/lamps-nginx/tree/master

    The key parts are:

    • Configure the docker-compose.yml to put all containers on the same network
    • Configure the Nginx to do the reverse proxy: It sends the address from the host to the containers and allows showing them without having to change ports.
    • Configure the web servers to serve the address.
    • Set the local address in the hosts.

    All containers in the same network: the docker-compose file

    In the docker-compose.yml, let's set the configuration to put all the servers are in the same network:

    version: '3'
    
    services:
      nginx:
        image: nginx
        container_name: nginx
        ports:
          - "80:80"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
        networks:
          - my_network <<<< Same Network
        depends_on:
          - web_server1
          - web_server2
          - mysql_server
    
      web_server1:
        [...]
        networks:
          - my_network <<<< Same Network
        depends_on:
          - mysql_server
    
      web_server2:
        [...]
        networks:
          - my_network <<<< Same Network
        depends_on:
          - mysql_server
    
      mysql_server:
        [...]
        networks:
          - my_network <<<< Same Network
        volumes:
          - ./mysql-data:/var/lib/mysql
    
    networks:
      my_network: <<<< Network name
        driver: bridge
    

    Reverse proxy to have all in the same 80 port: Nginx configuration

    The trickiest part of this solution was that I wanted all the servers on the 80 port, and being able to access them from a local address. To do so, we have to configure the nginx.conf file to send the traffic from the hosts to the containers.

    worker_processes 1;
    
    events {
        worker_connections 1024;
    }
    
    http {
          [...]
    
        server {
            listen 80;
            server_name app1.webserver.es; <<<< Address for webserver 1
    
            location / {
                proxy_pass http://web_server1;
                [...]
            }
        }
    
        server {
            listen 80;
            server_name app2.webserver.es; <<<< Address for Webser 2
    
            location / {
                proxy_pass http://web_server2;
                [...]
            }
        }
    
        server {
            listen 80;
            server_name mysql.webserver.es; <<<< Address for MySql
    
            location / {
                proxy_pass http://mysql_server;
                [...]
            }
        }
    }
    

    That will let the servers listening in their 80 ports without interfering with the 80 port of the host.

    Configure the web servers to serve the address

    In both web servers, I had to configure the server name to allow access:

    <VirtualHost *:80>
        ServerName app1.webserver.es <<<< The local name
        DocumentRoot /var/www/html
    
        <Directory /var/www/html>
            AllowOverride All
            Require all granted
        </Directory>
    </VirtualHost>
    

    Set the local address in the host

    And last, but not least, adding to /etc/hosts (I'm in Ubuntu) file the addresses to access them locally:

    127.0.0.1 app1.webserver.es
    127.0.0.1 app2.webserver.es
    127.0.0.1 mysql.webserver.es
    

    With that, when launching the server, it gives you a nice

    You can see a webserver showing a message that its connection to the database worked

    Thanks to all the people that helped me figuring out the answer.