Contents

Hi! In this post I’d like to show you how to configure Nginx to have many websites using the same host.

In reality we’d like to have 3 Docker containers with Nginx inside:

  1. website-a
  2. website-b
  3. reverse-proxy

This is website Dockerfile:

FROM node:12-alpine as build
WORKDIR /app
COPY . .


FROM nginx:stable-alpine
COPY --from=build /app/public /bin/www
COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD [ "nginx", "-g", "daemon off;" ]

In public directory is our website - HTML, CSS and JS files.

File called nginx.conf is a file in which Nginx configuration sits. Here is an example of such a file:

server {
    listen 80;
    location / {
        root /bin/www/;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }    
}

Above configuration simply consists pointer to the root folder containing website files.

Based on this configuration we can create images of our two websites - website-a and website-b.

This is a reverse proxy Dockerfile:

FROM nginx:stable-alpine

COPY ./main.conf /etc/nginx/conf.d/default.conf

CMD [ "nginx", "-g", "daemon off;" ]

It’s much simpler than the previous Dockerfile. Apart from the parent image it only contains Nginx configuration.

Here is an example of Nginx configuration for HTTP:

server {
    listen 80;
    server_name a.com www.a.com;
    
    location / {
        proxy_pass http://website-a;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }
}

server {
    listen 80;
    server_name b.com www.b.com;
    
    location / {
        proxy_pass http://website-b;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }
}

This is a modified version for HTTPS:

server {
    listen 80;
    server_name a.com www.a.com;
    return 301 https://$server_name$request_uri;
}
server {
    listen 80;
    server_name b.com www.b.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen              443 ssl;
    server_name a.com www.a.com;
    ssl on;
    ssl_certificate     /certs/a.crt;
    ssl_certificate_key /certs/a.key;
    
    location / {
        proxy_pass http://website-a;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }
}

server {
    listen              443 ssl;
    server_name b.com www.b.com;
    ssl on;
    ssl_certificate     /certs/b.crt;
    ssl_certificate_key /certs/b.key;
    
    location / {
        proxy_pass http://website-b;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }
}

To make it work we need to run containers. We achieve that using docker-compose:

version: '3'

services:
    website-a:
        image: website-a-image
    website-b:
        image: website-b-image
    reverse-proxy:
        image: reverse-proxy-image
        ports: 
            - 80:80
            - 443:443
        volumes:
            - ./certs:/certs
        links:
            - "website-a"
            - "website-b"

In ./certs directory on host machine we need to provide certificates for a.com and b.com. For development purpose it’s recommended to create self-signed certificates using OpenSSL command tool. Additionally to test the whole setup it’s also useful is configure local DNS - hosts file so that we can map a.com and b.com to 127.0.0.1.

Hope you enjoyed!