brew install nginx
Configuration file for nginx will be at /usr/local/etc/nginx/nginx.conf
Web apps can be stored at /usr/local/var/www
Start:
nginx
Stop:
nginx -s stop
Reload config:
nginx -s reload
Lint:
nginx -t
- Firewall was already disabled.
- Port forward 80 & 443 in router settings.
The full nginx.conf file will be at the end - this here is a basic proxy example.
In the block shown below - we created a web server:
1- 80 is the web server port.
2- localhost is where the web server is listening.
3- proxy_pass is the location we would like to proxy to. Should be the app server.
Therefore, this block is saying: proxy all requests at http://localhost:80 to http://localhost:3000.
# nginx.conf
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://192.168.100.190:3000;
}
}
The webserver server_name will usually point to a domain name - which DNS records should be set up for so it resolves to our public IP address. However, if that IP is dynamic its a problem as it eventually changes.
In my case, I had a domain with namecheap and they allow you to update the IP address that a special DNS record points to with a GET request.
Therefore, we can automate that process with a bash script and a cronjob:
#!/usr/bin/env sh
IP4=$(dig @resolver1.opendns.com ANY myip.opendns.com +short)
echo "$IP4"
URL="https://dynamicdns.park-your-domain.com/update?host=%40&domain=mydomain.com&password=mypassword&ip=""${IP4}"
echo "$URL"
curl --request GET \
--url $URL
Crontab:
- List cronjobs:
crontab -l
- Add cronjob (useful: https://crontab.guru)
crontab -e
Using Certbot (Let's Encrypt client) guide it is straightforward:
Install certbot:
brew install certbot
To only generate certificate:
sudo certbot certonly --standalone -d mydomain.com
To generate certificate and update nginx.conf file automatically:
sudo certbot --nginx
The location of the files generated will be at /etc/letsencrypt/archive. It also generates symbolic links to those files at /etc/letsencrypt/live.
To change our initial basic setup to use SSL and our domain name, this is how it would look like:
# nginx.conf
server {
listen 443 ssl;
server_name mydomain.com;
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
location / {
proxy_pass http://localhost:3000;
}
}
-
"Managed by certbot" is a line added by certbot automatically after adjusting your nginx.conf file if you ran the automatic command. Otherwise you can amend your nginx.conf manually to include your SSL certificates.
-
One issue faced here is that the user process running nginx did not have the required permissions to read the certificates (error when running nginx -t). Grant the necessary permissions using chmod on the real SSL files at /etc/letsencrypt/archive/mydomain.com/ and the symbolic ones at /etc/letsencrypt/live/mydomain.com/.
Perform a comprehensive SSL test using SSL Labs.
- 2 Apps on localhost 3000 and 5000.
- Each with own subdomain and SSL certificates.
- HTTP redirects to HTTPS.
#user nobody;
# Number of processes should not exceed number of cores #
worker_processes 1;
# MINIMUM (probably too low): worker_connections * 2 file descriptors = 512 #
# No need to multiply by worker_prcocesses as the limit is applied to each worker #
# 1 descriptor for client connection, 1 for proxied server #
# Could be more based on conf. Could be limited by system (ulimit -n) #
worker_rlimit_nofile 1024;
events {
# Default 1024 #
worker_connections 256;
}
# Error Log #
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
# Process ID Log #
pid logs/nginx.pid;
http {
include mime.types;
default_type application/octet-stream;
# Access Logs #
map $request_uri $loggable {
default 1;
~*\.(ico|css|js|gif|jpg|jpeg|png|svg|woff|ttf|eot)$ 0;
}
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$request_body_file"';
access_log logs/access.log main buffer=32k flush=30m if=$loggable;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# Max user upload size #
client_max_body_size 20M;
# Uploaded file RAM buffer instead of temp file #
client_body_buffer_size 20M;
# store request body in temp file for debugging #
# client_body_in_file_only on;
# Root domain HTTP #
server {
listen 80;
server_name mydomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 80;
server_name app1.mydomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 80;
server_name app2.mydomain.com;
return 301 https://$server_name$request_uri;
}
# Root domain HTTPS #
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
return 403;
}
}
# App 1 #
server {
listen 443 ssl;
server_name app1.mydomain.com;
ssl_certificate /etc/letsencrypt/live/app1.mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/app1.mydomain.com/privkey.pem; # managed by Certbot
location / {
proxy_pass http://localhost:3000;
}
}
# App 2 #
server {
listen 443 ssl;
server_name app2.mydomain.com;
ssl_certificate /etc/letsencrypt/live/app2.mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/app2.mydomain.com/privkey.pem; # managed by Certbot
location / {
proxy_pass http://localhost:5000;
}
}
}
-
Regex based HTTP redirects to HTTPS subdomains instead of multiple HTTP server blocks.
-
Wildcard SSL certificate instead of different SSL certificates for each subdomain.
-
The SSL certificate generated here achieves a rating of B on SSL labs. Todo for A+?