skip to Main Content

My project is using CI/CD for deployment and I have one docker-compose file for each application stage (dev, staging, release).

Depending on what stage the application is, I want to redirect the user for my API using Nginx for a different ip/port.

On my default.conf file I want to write something like this.

server {
    listen       443 ssl;

    ssl_certificate /etc/ssl/server/cert.pem;
    ssl_certificate_key /etc/ssl/server/privkey.pem;

    location / {
        proxy_pass https://api:$API_PORT;
        proxy_set_header Host $host;
        ...

where api is a reference for my service’ IP that is defined in my docker-compose file and I want ${API_PORT} to be a reference to my environment variable that is defined inside docker-compose.

My docker-compose file looks like this.

version: "3"

services:
  api:
    ...
  ports:
      - 4000:4000
  nginx:
    ...
    environment:
      - API_PORT=4000
    ports:
      - 5180:80
      - 5181:443

How could I achieve that?

Note: If I have a static port, for example 4000, when I up both stage and release versions I will have conflicts on port 4000.

2

Answers


  1. Chosen as BEST ANSWER

    For accomplishing that you will need to set your Dockerfile and rename your .conf file in order to Nginx understand what you want to do.

    First, Nginx by itself supports what you want to do, so you will need to use templates for that.

    By default, if you place your config files inside /etc/nginx/templates and your filename ends with .template, Nginx will use envsubst to substitute your environment variable inside your .conf file for the values that you define in your docker-compose file.

    So let's have an example.

    You have default.conf.template (don't forget to rename your .conf files) file with your Nginx settings:

    server {
        listen       443 ssl;
    
        ssl_certificate /etc/ssl/server/cert.pem;
        ssl_certificate_key /etc/ssl/server/privkey.pem;
    
        location / {
            proxy_pass https://api:$API_PORT;
            proxy_set_header Host $host;
            ...
    

    Your Dockerfile will copy your default.conf.template file and will paste it inside /etc/nginx/templates

    ...
    COPY /your/nginx/settings/folder/default.conf.template /etc/nginx/templates
    ...
    

    With that done, when Nginx starts running it will search on the templates folder for *.template files, and when it finds your default.conf.template file it will replace the environment variables reference for the actual value and will move this file for /etc/nginx/conf.d folder.

    So if your docker-compose file looks like this:

    version: "3"
    
    services:
      api:
        ...
      ports:
          - 4000:4000
      nginx:
        ...
        environment:
          - API_PORT=4000
    

    your default.conf.template file (mentioned above) will be renamed to default.conf, moved to /etc/nginx/conf.d/ and will look like this:

    location / {
          proxy_pass https://api:4000;
          ...
    

    So Nginx will replace the references for the values and move the .conf files to the right place.


  2. In your Nginx configuration, you don’t need to do anything; use the fixed port 4000.

    proxy_pass https://api:4000;
    

    Since this is a connection from the Nginx container to the API container, it stays within the Docker network environment. This connection doesn’t pay any attention to what you might have set as ports:, it connects to the server process listening on port 4000 in the API container.

    When you start the API container, the server process inside the container should use that same fixed port 4000. If you need to make the API container externally visible, you may choose a different number for the first port in the ports: block, but the second port needs to be 4000.

    services:
      api:
        ports: ['4001:4000']
      nginx:
        ports: ['5180:80', '5181:443']
    

    If you need to launch multiple copies of this stack, you need to change the first port number in all of the ports: blocks, but leave the second numbers unchanged.

    If all access to the API container is through this Nginx proxy, you may not need the api: { ports: [] } block at all, and you can safely delete it; again, it’s not used for connections between containers.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search