skip to Main Content

I use Swarmpit to control Swarm nodes.

There are multiple stacks on Swarm (one for each application) and another stack with NGINX. All the stacks are attached to one external docker network named "public".

The web applications is a Laravel application (Octane) serverd on port 9000 (It is reachable from IP:9000).

NGINX is reachable on port 80

I need to serve all the apps through NGINX.

Web Application docker-compose.yml

version: '3.3'
services:
  laravel:
    image: myimage:latest
    extra_hosts:
     - host.docker.internal:host-gateway
    environment:
      CHOKIDAR_USEPOLLING: 'true'
      WWWUSER: '1000'
      XDEBUG_CONFIG: client_host=host.docker.internal
      XDEBUG_MODE: 'off'
    ports:
     - 5173:5173
     - 9000:9000
    networks:
     - net
     - public
    logging:
      driver: json-file
  mongo:
    image: mongo:latest
    command:
     - --quiet
     - --logpath
     - /dev/null
    environment:
      ME_CONFIG_MONGODB_ADMINPASSWORD: ...
      ME_CONFIG_MONGODB_ADMINUSERNAME: ...
      MONGO_INITDB_DATABASE: ...
      MONGO_INITDB_ROOT_PASSWORD: ...
      MONGO_INITDB_ROOT_USERNAME: ...
    ports:
     - 27017:27017
    volumes:
     - mongo:/data/db
    networks:
     - net
    logging:
      driver: json-file
  mysql:
    image: mysql:8
    environment:
      MYSQL_DATABASE: ...
      MYSQL_PASSWORD: ...
      MYSQL_ROOT_PASSWORD: ...
      MYSQL_USER: ...
    ports:
     - 3306:3306
    volumes:
     - mysql:/var/lib/mysql
    networks:
     - net
    logging:
      driver: json-file
networks:
  net:
    driver: overlay
  public:
    external: true
volumes:
  mongo:
    driver: local
  mysql:
    driver: local

NGINX docker-compose.yml

version: '3.3'
services:
  webserver:
    image: mycustomnginximage:latest
    ports:
     - 80:80
     - 8080:8080
     - 443:443
    networks:
     - global
     - public
    logging:
      driver: json-file
networks:
  global:
    driver: overlay
  public:
    external: true

NGINX server conf

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    server_name mywebsite.dev *.mywebsite.dev;
    server_tokens off;
    root /home/forge/domain.com/public;

    # SSL configuration
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/nginx/certificates/mywebsite.pem;
    ssl_certificate_key /etc/nginx/certificates/mywebsite.key;

    index index.php;

    charset utf-8;

    location /index.php {
        try_files /not_exists @octane;
    }

    location / {
        try_files $uri $uri/ @octane;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/domain.com-error.log error;

    error_page 404 /index.php;

    location @octane {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://my_swarm_service_name:9000;
    }
}

The result is that the application is reachable directly through IP:9000 but not through https://mywebsite.dev As if nginx couldn’t divert traffic to the service.

enter image description here

I’ve tryied with:

proxy_pass http://my_swarm_service_name:9000;
proxy_pass http://localhost:9000;
proxy_pass http://docker.service.internal.ip:9000;

How should i use the proxy_pass directive? Or there are something else wrong?

2

Answers


  1. The service name is laravel so, to access the service vip you could use the following hostnames:

    # Each service is available using its plain service name
    proxy_pass http://laravel:9000
    # If you have multiple laravels in multiple stacks, you can name the specific one you
    # want. Assuming you have deployed a stack called appstack1
    proxy_pass http://appstack1_laravel:9000
    # Docker also allows you to specify which network, this can help resolve ambiguities,
    #i.e. prevent picking up an unwanted other laravel registered on the global network.
    proxy_pass http://laravel.public:9000
    

    None of this is going to work out the box however until you add the most crucial piece: Nginx does not do dns resolution at runtime of docker service names unless you tell it to.

    You need to configure the resolver Nginx uses to point to dockers container dns:

    server {
      resolver 127.0.0.11;
    }
    
    Login or Signup to reply.
  2. As they are in the same docker network, you can use either the name of your service which is inside the docker-compose, or using the taken IP by docker (docker default IP is 172.17.0.1).

    So it could be as follows:

    proxy_pass http://laravel:9000;
    

    or

    proxy_pass http://172.17.0.1:9000;
    

    Also, you can test it inside the nginx container via ping:

    docker exec -it <nginx container id or name> bash
    ping laravel
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search