Using both nginx template feature and a reloading solution

1.7k Views Asked by At

I have a docker project using both nginx and let's encrypt with certbot. I'm quite new to docker, and for my nginx image, I'm using the feature that is helping me to use environment variables in nginx configuration.

On a famous tutorial, they use this command to start nginx and reload it automatically

command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

The problem is that when I'm using this command instead of the basic one my template is no longer converted to a working nginx conf.

I want to be able to reload nginx but I also want nginx to transform my template in a valid nginx configuration.

How can I achieve that please ?

Here is my docker-compose.yml

version: '3'

services:
  db:
    image: mysql
    environment:
      - MYSQL_DATABASE=${DATABASE_NAME}
      - MYSQL_USER=${DATABASE_USER}
      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DATABASE_ROOT_PASSWORD}
    ports:
      - "3306:3306"
    volumes:
      - ./db/data:/var/lib/mysql

  adminer:
    image: adminer
    restart: always
    environment:
      - ADMINER_DESIGN=lucas-sandery
    ports:
      - 8080:8080

  php-fpm:
    build:
      context: ./php-fpm
    depends_on:
      - db
    environment:
      - APP_ENV=${APP_ENV}
      - APP_SECRET=${APP_SECRET}
      - DATABASE_URL=mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@db:3306/${DATABASE_NAME}?serverVersion=5.7
    volumes:
      - ../app:/var/www

  node:
    image: node:alpine
    volumes:
      - ../app:/var/www
    working_dir: /var/www
    command: "/bin/sh -c 'yarn install ; yarn run watch'"

  nginx:
    image: nginx:alpine
    volumes:
      - ../app:/var/www
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/templates:/etc/nginx/templates
      - ./logs:/var/log
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    depends_on:
      - php-fpm
    ports:
      - "80:80"
      - "443:443"
    environment:
      - APP_DOMAIN=${APP_DOMAIN}

  certbot:
    image: certbot/certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

And my site.template.conf file

upstream php-upstream {
    server php-fpm:9000;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name ${APP_DOMAIN};

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server ipv6only=on;

    ssl_certificate /etc/letsencrypt/live/${APP_DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${APP_DOMAIN}/privkey.pem;

    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    server_name ${APP_DOMAIN};
    root /var/www/public;
    index index.php index.html index.htm;

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

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

Thanks

2

There are 2 best solutions below

6
On

You can add a restart: always in the docker-compose.yml nginx section to handle service exits by errors, and also if you want to trigger it manually you can issue a docker-compose restart nginx in shell at the folder you have the yml file.

I don't know if you've intentionally left out of your question sensitive information like ${APP_DOMAIN}, but if you want to insert these values you can use docker secrets. You can read more about docker secrets here: https://docs.docker.com/engine/swarm/secrets/

(Hint: you don't need to use swarm to have secrets, at the end of this link there is a docker-compose example. As long as you start the services with it you don't need swarm).

EDIT

So the issue is you can't substitute environment variables on a nginx conf file. have you seen this: https://github.com/docker-library/docs/tree/master/nginx#using-environment-variables-in-nginx-configuration-new-in-119 ?

I found this information here: https://serverfault.com/a/1022249/80400


If you want to reload nginx at every 6h, why don't you use a crontab ? You can keep everything as it is and do in the crontab:

* */6 * * * cd /home/to/docker-compose.yml/ && docker-compose exec nginx -s reload > /var/log/reloading_nginx.log

(I think docker-compose exec is the right command instead of docker-compose run).

0
On

Problem is in this line, docker-entrypoint.sh wont trigger if your commands first argument is not nginx or nginx-debug, and yours is /bin/bash.

In order to run entrypoint as well change your command to: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & /docker-entrypoint.sh nginx -g \"daemon off;\"'"