NGINX on Host System as Proxy for WordPress Container

Hello,

I am running an NGINX server on my host system and it serves multiple applications. The host system has one IP that I cannot add more IP’s to it.

I used “docker compose” to build 2 containers for WordPress+MySQL.

I understand that the containers will communicate over the docker-network.

How to get the NGINX server to communicate with the WordPress container?

I know it maybe not the best solution, but it is the situation I am in and will appreciate the guidance to achieve this setup.

So, Help!

I googled “docker network getting started” for you.

This is the first hit. Check the section “use-user-defined-bridge-networks”:

Thank you for the answer @meyay . I tried different options and never worked for me!

What I am asking for is guidance on a specific use case.

Anyone who did this before?

Almost Everyone? It is just so basic, that I though pointing you to the documentation that actually shows all steps, would be enough for you to understand. Apparently It is not.

How about instead you share the exact commands you used, so we can understand what you did and how you did it + the ouput of the commands. This allows us to understand your situation and make recommendations based on that.

Update: my bad. For whatever reason I though you do use docker run instead of docker compose.
@rimelek made me realize I ignored that you use docker compose. Thus, I posted a link to the the wrong documentation.

Docker compose takes care of creating user defined network already. User defined networks have build-in dns-based service discovery. Simply use the service name of the mysql container in your wordpress container to access the mysql container. In case this is still unclear, please share the content of your exact compose file, so we can make recommendations based on your actual file.

Do you mean you have NginX installed without containers from a package manager’s repository and you need a way to forward requests to wordpress which runs in a container?

You can forward a port from localhost to the container:

ports:
  - 127.0.0.1:8081:80

And configure nginx to forward requests to 127.0.0.1:8081. Or run nginx in a container, let it automatically discover containers and add extra configurations to forward requests to the hosts IP address for services not running in containers. The first solution would be probably easier for you.

1 Like

Thank you for pitching in @rimelek! I am not sure how I managed to be on the wrong track during the whole topic. I shouldn’t respond to topics when I am tired and just skim through topics, instead of reading them completely.

@knimer: sorry for that!

Hello

Thank you @meyay @meyay

No worries, I am not an expert, yet was trying my best and no worries.

Here are my configs:

On the Host server, NGINX config is:

upstream wordpress {
        server localhost:9070;
}

server {
	listen 80;
	listen [::]:80;
	server_name xyz.example.com;
	return 301 https://$host$request_uri;
}

server {
        listen 443;
        listen [::]:443;

        server_name http://xyz.example.com;

	ssl_certificate /etc/letsencrypt/live/wildcard.example.com-0001/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/wildcard.example.com-0001/privkey.pem;
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384";
	ssl_prefer_server_ciphers on;
	ssl_session_cache shared:SSL:10m;
	ssl_verify_depth 3;
	ssl_dhparam /etc/nginx/dhparam.pem;

        index index.php index.html index.htm;

        root /var/www/html;

	add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;
        add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;

        location ~ /.well-known/acme-challenge {
                allow all;
                root /var/www/html;
        }

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
        }

        location ~ /\.ht {
                deny all;
        }
        
        location = /favicon.ico { 
                log_not_found off; access_log off; 
        }
        location = /robots.txt { 
                log_not_found off; access_log off; allow all; 
        }
        location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
                expires max;
                log_not_found off;
        }
}

Now, the docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress:
    depends_on:
      - db
    image: wordpress:6.2.2-php8.0-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    ports:
      - "127.0.0.1:9070:9070"
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - /var/www/html:/var/www/html

volumes:
  dbdata:

networks:
  app-network:
    driver: bridge

When I try to access xyz.example.com, I get:

502 Bad Gateway

In the NGINX error.log with log level “info”, I can see:

2023/08/09 19:47:51 [error] 17181#17181: *1 connect() failed (111: Unknown error) while connecting to upstream, client: 186.79.201.000, server: http://xyz.example.com, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9070", host: "xyz.example.com"

For “docker compose ps”, I get:

NAME                IMAGE                               COMMAND                  SERVICE             CREATED             STATUS              PORTS
db                  mysql:8.0                           "docker-entrypoint.s…"   db                  29 minutes ago      Up 3 seconds        3306/tcp, 33060/tcp
wordpress           wordpress:6.2.2-php8.0-fpm-alpine   "docker-entrypoint.s…"   wordpress           29 minutes ago      Up 3 seconds        9000/tcp, 127.0.0.1:9070->9070/tcp

For “docker network ls”:

NETWORK ID     NAME                    DRIVER    SCOPE
a8d2d5803b41   bridge                  bridge    local
c577a7812f2c   host                    host      local
82629c23af3d   none                    null      local
5a1e235c2f82   wordpress_app-network   bridge    local
ee559d7c813c   wordpress_default       bridge    local

For “docker network inspect wordpress_app-network”:

[
    {
        "Name": "wordpress_app-network",
        "Id": "5a1e235c2f82c9889d336920be40312d3b20c70d80b9a2e6c04c58d71e3526d4",
        "Created": "2023-08-09T19:22:23.551479464Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "baab7f2a5cc9a2deb0581184b61c5c33b24c97078c61203722e09e6aa24afcb8": {
                "Name": "db",
                "EndpointID": "5a4cbbaa0bb368dc8e926cf56518cdfd68dd32b4246e79c071b54d5783dd74da",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "app-network",
            "com.docker.compose.project": "wordpress",
            "com.docker.compose.version": "2.20.2"
        }
    }
]

The same for the other network “wordpress_default”:

[
    {
        "Name": "wordpress_default",
        "Id": "ee559d7c813ce48ece88cdd7f2949cfde037530f1213a5c54a3fe49ffbf38137",
        "Created": "2023-08-09T19:22:23.609158268Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "530ecaf6fb4d7d10900960857ed47b4163661c789a347b1315916ac854e4ec5c": {
                "Name": "wordpress",
                "EndpointID": "c29dc63c242e10002545d256cd681083f95e00fa099b6ceef0d463465bb61805",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "wordpress",
            "com.docker.compose.version": "2.20.2"
        }
    }
]

Last notes:

- I can see that none of the “networks” is binding to 127.0.0.1
- The wordpress container connects to port 9000 despite the docker compose YML file indicates different ports setup!

I hope the above shows in detail the setup that I have.

Let me know if anything else can help with this.

Thanks a lot
Khaldoun

Thank you for sharing the details!

It looks like, instead of:

You need to use:

      - "127.0.0.1:9070:9000"

Which is correct, because it doesn’t know anything about the host port you bound to the host ip 127.0.0.1. The published port is not related to the network, it is related to the container.

That’s high likely due to default parameters. I haven’t checked if the image provides an environment variable to set the container port (and override it in a config file).

Though, unless you are using --network host, or connect your container to a macvlan or ipvlan network, there is no reason to change the container port at all.

Thank you so much @meyay

I needed to amend the docker-compose.yml by adding the following:

    networks:
      - app-network

So, the full file is:

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress:
    depends_on:
      - db
    image: wordpress:6.2.2-php8.0-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    ports:
      - "127.0.0.1:9070:9000"
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
      - WORDPRESS_CONFIG_EXTRA=$MYWP_EXTRA_CONFIG
    volumes:
      - /var/www/html:/var/www/html
    networks:
      - app-network

volumes:
  dbdata:

networks:
  app-network:
    driver: bridge

So, the container is using the same network bridge. Without it, I got a “DB Connection Error” from Wordpress.

I hope someone else will benefit from the above.

And thanks again.

Great that it works now.

I didn’t spot that only db service was attached to the network, and the wordpress service wasn’t. Of course the containers need to share a network in order to communicate with each other.

Though, if you only work with a single network, you don’t have to create a network, and don’t need to attach the services to it. Compose deployments always create a default network, and attach the services to the default network, unless you specify a network, like you did with the db service.