This is an example of hosting standalone web front-end (web) and data API (api) applications under the same domain via Nginx (acting as a reverse proxy) and Docker, where HTTP requests starting with example.com/graphql
and example.com/login/*
are being redirected to http://api:3000 and everything else under the same domain is going to be passed to http://web:3000.
.
├── /nginx.sites/ # Server configuration for each of web apps
├── /nginx.snippets/ # Nginx code snippets
├── docker-compose.yml # Defines Docker services, networks and volumes
└── nginx.config # Top-level Nginx configuration
version: '3'
volumes:
data:
redis:
services:
nginx:
image: nginx:1.11.10-alpine
links:
- api
- web
read_only: true
tmpfs:
- /var/cache/nginx
- /var/log/nginx
- /var/run
volumes:
- ./nginx.snippets:/etc/nginx/snippets:ro
- ./nginx.sites:/etc/nginx/sites-enabled:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
- /etc/ssl/certs/dhparam.pem:/etc/ssl/certs/dhparam.pem:ro
- /var/www:/var/www
ports:
- '80:80'
- '443:443'
db:
image: postgres:9.6.2-alpine
restart: always
environment:
- POSTGRES_PASSWORD=xxx
read_only: true
tmpfs:
- /tmp
- /var/run/postgresql
volumes:
- data:/var/lib/postgresql/data
redis:
image: redis:3.2.8-alpine
restart: always
read_only: true
volumes:
- redis:/data
web:
image: web
read_only: true
restart: always
environment:
- PORT=3000
- NODE_ENV=production
expose:
- '3000'
api:
image: api
read_only: true
restart: always
depends_on:
- db
- redis
links:
- db
- redis
environment:
- PORT=3000
- NODE_ENV=production
- NODE_DEBUG=false
- WEBSITE_URL=https://example.com
- FRONTEND_HOST_WHITELIST=localhost
- DATABASE_URL=postgres://user:xxx@db:5432/api
- DATABASE_DEBUG=false
- REDIS_URL=redis://redis:6379/1
- SESSION_SECRET=xxx
- FACEBOOK_ID=xxx
- FACEBOOK_SECRET=xxx
- GOOGLE_ID=xxx
- GOOGLE_SECRET=xxx
- TWITTER_KEY=xxx
- TWITTER_SECRET=xxx
expose:
- '3000'
# ports:
# - '0.0.0.0:9229:9229' # V8 inspector
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.example.com;
include snippets/ssl-example.com.conf;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
include snippets/ssl-example.com.conf;
root /var/www/example.com;
location ~ /.well-known {
allow all;
}
location ~ ^/login/.+ {
include snippets/proxy-params.conf;
proxy_pass http://api:3000;
}
location /graphql {
include snippets/proxy-params.conf;
proxy_pass http://api:3000;
}
location / {
include snippets/proxy-params.conf;
proxy_pass http://web:3000;
}
}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_max_temp_file_size 0;
proxy_redirect off;
proxy_read_timeout 240s;
# https://cipherli.st/
# https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now. You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
include snippets/ssl-params.conf;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
Thank you for providing this. I'd suggest removing
/var/log/nginx
fromnginx.tmpfs
. That way the nginx logs are sent to the docker logs.