This article provides a template to easily configure the deployment of multiple websites on one server IP or on one droplet from digitalocean. Reverse-proxy, nginx configuration files and SSL certificate are created automatically for each website running in a Docker container.

Contents:
Prerequisites
Required tools and create domain names
- Git, docker and docker-compose are installed on your server
- Several websites run inside Docker containers on a single server. (Each one could either be a static files server, or WordPress running on Apache, etc.
- The domain name for each website is configured to point to the IP of the server. Your host must be publicly reachable on both port 80and443. Check your firewall rules to make sure that these ports are open.
- Create a website directory and set up proper permissions. In this tutorial, we’ll assume that the web directory is at /srv/www
Step 1: Create websites directories
Read more: Create a website directory and set up proper permissions
# 0. settings
web_dir=/srv/www
myusername=kassambara
# 1. Create the website directory
sudo mkdir -p $web_dir
# 2. set your user as the owner
sudo chown -R $myusername $web_dir
# 3. set the web server as the group owner
sudo chgrp -R www-data $web_dir
# 4. 755 permissions for everything
sudo chmod -R 755 $web_dir
# 5. New files and folders inherit 
# group ownership from the parent folder
chmod g+s $web_dirStep 2: Download a template
Download a template into your website directories www
web_dir=/srv/www
git clone https://github.com/kassambara/nginx-multiple-https-websites-on-one-server $web_dirStep 3: Inspect the project structure and configuration files
Project Structure
www
├── README.Rmd
├── README.md
├── nginx-proxy
│   ├── certs
│   ├── conf.d
│   ├── docker-compose.yml
│   ├── html
│   ├── nginx.tmpl
│   └── vhost.d
├── your-website-one.com
│   ├── docker-compose.yml
│   └── index.html
└── your-website-two.com
    ├── docker-compose.yml
    └── index.htmlInside /nginx-proxy, there are four empty directories: conf.d, vhost.d, html and certs. These are used to store the nginx and the Let’s Encrypt configuration files.
Inspect the docker-compose.yml configuration file
Inside /nginx-proxy/, there is a docker-compose.yml file with this content:
version: '3.6'
services:
  nginx:
    image: nginx
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"
    container_name: nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d:/etc/nginx/conf.d
      - ./vhost.d:/etc/nginx/vhost.d
      - ./html:/usr/share/nginx/html
      - ./certs:/etc/nginx/certs:ro
  nginx-gen:
    image: jwilder/docker-gen
    command: -notify-sighup nginx -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
    container_name: nginx-gen
    restart: unless-stopped
    volumes:
      - ./conf.d:/etc/nginx/conf.d
      - ./vhost.d:/etc/nginx/vhost.d
      - ./html:/usr/share/nginx/html
      - ./certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro
  nginx-letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nginx-letsencrypt
    restart: unless-stopped
    volumes:
      - ./conf.d:/etc/nginx/conf.d
      - ./vhost.d:/etc/nginx/vhost.d
      - ./html:/usr/share/nginx/html
      - ./certs:/etc/nginx/certs:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      NGINX_DOCKER_GEN_CONTAINER: "nginx-gen"
      NGINX_PROXY_CONTAINER: "nginx"
networks:
  default:
    external:
      name: nginx-proxyThis will launch three services:
- nginx: the nginx-reverse proxy, uses the default nginx image. The label is needed so that the letsencrypt container knows which nginx proxy container to use.
- nginx-gen: uses the jwilder/docker-gen image. Its command instruction will render a nginx configuration (based on nginx.tmpl) for each website / container added to the network.
- nginx-letsencrypt: generates and renew the HTTPS certificates.
All these services are bound to the nginx-proxy network.
Update nginx.tmpl: Nginx configuration file template
Inside /nginx-proxy/, there is a nginx.tmpl file. This is the used by the nginx-gen container to create the nginx configuration file for each website / container added to the network.
Download the latest updated version from Github here:
# Remove old version
rm -rf $web_dir/nginx-proxy/nginx.tmpl
# Download new version
curl -s https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl> $web_dir/nginx-proxy/nginx.tmplStep 4: Run the nginx reverse proxy
# 1. Create the docker network
docker network create nginx-proxy
# 2. Create the reverse proxy with the 
# nginx, nginx-gen and nginx-letsencrypt containers
cd /srv/www/nginx-proxy/
docker-compose up -dStep 5: Link a website to the running nginx-proxy
The docker-compose.yml file of the website, you want to link, should include the following instructions provided in the template available in the folder your-website-one.com (not the one from nginx-proxy above). The content of the template looks like this:
version: '3.6'
services:
  my-app:
    image: nginx
    restart: always
    environment:
      # NGINX-PROXY ENVIRONMENT VARIABLES: UPDATE ME
      - VIRTUAL_HOST=your-website-one.com 
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=your-website-one.com 
      - LETSENCRYPT_EMAIL=your.email@domain.com
      # END NGINX-PROXY ENVIRONMENT VARIABLES
    expose:
      - 80
networks:
  default:
    external:
      name: nginx-proxy- Environment variables:
- VIRTUAL_HOST: your domain name, used in the nginx configuration.
- VIRTUAL_PORT: (optional) the port your website is listening to (default to 80).
- LETSENCRYPT_HOST: your domain name, used in the Let’s Encrypt configuration.
- LETSENCRYPT_EMAIL: your email, used in the Let’s Encrypt configuration.
 
- Ports:
- the exposed port (here 80) should be the same as the VIRTUAL_PORTabove.
 
- the exposed port (here 80) should be the same as the 
- Network:
- your website container should be linked to the external docker network named nginx-proxy
 
- your website container should be linked to the external docker network named 
Once the update of the docker-compose.yml file is done, you can start the website with:
cd /srv/www/your-website-one.com
docker-compose up -dThe website is automatically detected by the reverse proxy, has a HTTPS certificate and is visible at https://your-website-one.com.
You can repeat this last step for any other container you want to proxy
Frequently asked question
How to redirect from http non-www to https www?
If you have control of the DNS record, the best practice is to take care it with an ALIAS ( or CNAME). See discussion.
Solution 1. Use redirect container. Catch all http redirect, useful for http -> https redirects. Insanely fast and small! Based on alpine and nginx. Source: cusspvz/redirect.docker
version: '3.6'
services:
  www.omicstudio.com:
    image: nginx
    restart: always
    volumes:
      - "./:/usr/share/nginx/html"
    environment:
      - VIRTUAL_HOST=www.omicstudio.com
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=www.omicstudio.com
      - LETSENCRYPT_EMAIL=alboukadel.kassambara@gmail.com
  # redirect omicstudio.com to www.omicstudio.com
  omicstudio.com:
    image: cusspvz/redirect
    restart: always
    environment:
      - VIRTUAL_HOST=omicstudio.com
      - VIRTUAL_PORT=80
      - HTTPS_METHOD=noredirect
      - LETSENCRYPT_HOST=omicstudio.com
      - REDIRECT=https://www.omicstudio.com
      # See available redirect parameters: https://github.com/cusspvz/redirect.docker
      - WORKER_CONNECTIONS=1024
      
networks:
  default:
    external:
      name: nginx-proxySolution 2. see this merge request: Added VIRTUAL_HOST_ALIAS support
Recommended for you
This section contains best data science and self-development resources to help you on your path.
Books - Data Science
Our Books
- Practical Guide to Cluster Analysis in R by A. Kassambara (Datanovia)
- Practical Guide To Principal Component Methods in R by A. Kassambara (Datanovia)
- Machine Learning Essentials: Practical Guide in R by A. Kassambara (Datanovia)
- R Graphics Essentials for Great Data Visualization by A. Kassambara (Datanovia)
- GGPlot2 Essentials for Great Data Visualization in R by A. Kassambara (Datanovia)
- Network Analysis and Visualization in R by A. Kassambara (Datanovia)
- Practical Statistics in R for Comparing Groups: Numerical Variables by A. Kassambara (Datanovia)
- Inter-Rater Reliability Essentials: Practical Guide in R by A. Kassambara (Datanovia)
Others
- R for Data Science: Import, Tidy, Transform, Visualize, and Model Data by Hadley Wickham & Garrett Grolemund
- Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems by Aurelien Géron
- Practical Statistics for Data Scientists: 50 Essential Concepts by Peter Bruce & Andrew Bruce
- Hands-On Programming with R: Write Your Own Functions And Simulations by Garrett Grolemund & Hadley Wickham
- An Introduction to Statistical Learning: with Applications in R by Gareth James et al.
- Deep Learning with R by François Chollet & J.J. Allaire
- Deep Learning with Python by François Chollet
Version: 
     Français
Français
 
                                 
                             
					
`chmod g+s $web_dir` is not working. You should use `sudo chmod g+s $web_dir`
There has been an update to the nginx-letsencrypt docker: it is essential now to also mount volume ./acme:/etc/acme.sh, or else the docker image will fetch a new certificate from letsencrypt on every restart – and that will quickly exceed the allowed 5 certs/week.
Thank you for your valuable comment. We’ll update ASAP.