Skip to content

Instantly share code, notes, and snippets.

@doraeminemon
Last active July 18, 2019 07:30
Show Gist options
  • Save doraeminemon/98c9948b26c1b77a41f151f6ecb4430d to your computer and use it in GitHub Desktop.
Save doraeminemon/98c9948b26c1b77a41f151f6ecb4430d to your computer and use it in GitHub Desktop.
Deployment with SSL, NGINX, docker-compose checklist

Deployment with SSL checklist

  • Mapped domain to server's IP
  • SSH to server and run generate_cert.sh ( dry-run first, then actual )
  • Copy cert file to accessible location by nginx
  • Config nginx location correctly to cert and to proxy server
  • Config docker-compose file to complete this checklist :
  • Service name and port mapping matched nginx.conf
  • Dockerize so that nginx wait for service to come up
  • Additional CORS header config in server and nginx.conf
  • Docker-compose up -d on server
version: "3.5"
services:
nginx:
image: placeholder-nginx:latest
build:
context: './nginx'
volumes:
- ./nginx/:/etc/nginx/
- ./keys/letsencrypt/:/etc/letsencrypt/
ports:
- 443:443
- 80:80
networks:
- backend
web: # Service name to be mapped correctly with nginx.conf
image: placeholder-web:latest
build:
context: './'
expose:
- "3000" # This port should be mapped correctly with nginx.conf file
networks:
- backend
deploy:
replicas: 1
update_config:
delay: 10s
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
env_file:
- .env
command: dockerize -wait tcp://db:5432 npx nps start
# using dockerize instead of depends_on directive to be
# compatible with multiple docker-compose file versions
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
env_file:
- .env
networks:
- backend
networks:
backend:
volumes:
db-data:
#!/bin/bash
sudo docker run -it --rm --name certbot \
-p 80:80 -p 443:443 \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
certbot/certbot certonly --dry-run
# Try with letsencrypt staging server first with --dry-run, then
# when success, actually generate it without --dry-run (
# to prevent being blocked after too many failed attempts )
error_log /var/log/nginx/error.log debug;
# replace all placeholder with your domain name
events {
worker_connections 1024; ## Default: 1024
multi_accept on;
}
http {
# Don't send any server info in the headers, only "nginx"
server_tokens off;
# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Send the client a "request timed out" if the body is not loaded by this time.
client_body_timeout 30;
# If the client stops reading data, free up the stale client connection after this much time. Default 60.
send_timeout 10;
gzip on;
gzip_disable msie6;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
log_format host_timed '$http_host "$request" $status '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time $body_bytes_sent';
log_format debug_503 '[$time_local] $http_user_agent $remote_addr'
' [$request] s:$status r:$request_completion'
' t:$request_time rtt:$tcpinfo_rtt b:$bytes_sent';
access_log off;
fastcgi_cache_path /usr/share/nginx/cache levels=1:2 keys_zone=microcache:10m max_size=1024m inactive=1h;
server {
listen 80;
listen [::]:80;
server_name api.placeholder.com;
location / {
proxy_pass http://web:3000/api;
proxy_pass_header server;
}
}
# SSL configuration
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name api.placeholder.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/api.placeholder.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/api.placeholder.com/privkey.pem; # managed by Certbot
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# Improve HTTPS performance with session resumption
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Enable server-side protection against BEAST attacks
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384"; # change this to a randomly generated hash
# RFC-7919 recommended: https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe4096
# ssl_dhparam /etc/ssl/ffdhe4096.pem;
# ssl_ecdh_curve secp521r1:secp384r1;
location /api {
# Aditional Security Headers
# ref: https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
# ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
add_header X-Frame-Options DENY always;
# ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
add_header X-Content-Type-Options nosniff always;
# ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
add_header X-Xss-Protection "1; mode=block" always;
proxy_pass http://web:3000/api;
proxy_pass_header server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($http_origin ~* (.*\.(placeholder).com)) {
set $cors "true";
}
if ($cors = "true") {
add_header Access-Control-Allow-Origin "$http_origin";
add_header Access-Control-Allow-Methods GET,PUT,POST,DELETE;
add_header Access-Control-Allow-Headers "Content-Type, User-Agent, Content-Type";
add_header Content-Security-Policy upgrade-insecure-requests;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment