NGINX Proxy: Difference between revisions
mNo edit summary |
mNo edit summary |
||
Line 2: | Line 2: | ||
The following configs can be used to proxy connections from another application via NGINX. You can couple this with the Let's Encrypt Certbot and its NGINX plugin to create an SSL proxy for apps. | The following configs can be used to proxy connections from another application via NGINX. You can couple this with the Let's Encrypt Certbot and its NGINX plugin to create an SSL proxy for apps. | ||
'''''Note: You will need to modify these files to reflect the hostnames, fully qualified domains names (FQDNs), and IPs of the systems you use this on. Items that need to be changed are shown using generic placeholders (demo.example, <stuff in brackets>, etc). Ensure that you fully read through all the configuration files before running and don't just copy and paste what you see here. This information is provided AS IS and there are plenty of resources available online if you run into problems.''''' | '''''Note: You will need to modify these files to reflect the hostnames, fully qualified domains names (FQDNs), and IPs of the systems you use this on. Items that need to be changed are shown using generic placeholders (demo.example.com, <stuff in brackets>, etc). Ensure that you fully read through all the configuration files before running and don't just copy and paste what you see here. This information is provided AS IS and there are plenty of resources available online if you run into problems.''''' | ||
'''''This information has been pulled from various sources and is essentially notes on how to setup an NGINX reverse proxy. This is not a complete how-to guide and you are assumed to already know how to setup/configure/use nginx, docker, openssl, certbot (let's encrypt), etc.''''' | '''''This information has been pulled from various sources and is essentially notes on how to setup an NGINX reverse proxy. This is not a complete how-to guide and you are assumed to already know how to setup/configure/use nginx, docker, openssl, certbot (let's encrypt), etc.''''' |
Latest revision as of 06:00, 16 February 2024
The following configs can be used to proxy connections from another application via NGINX. You can couple this with the Let's Encrypt Certbot and its NGINX plugin to create an SSL proxy for apps.
Note: You will need to modify these files to reflect the hostnames, fully qualified domains names (FQDNs), and IPs of the systems you use this on. Items that need to be changed are shown using generic placeholders (demo.example.com, <stuff in brackets>, etc). Ensure that you fully read through all the configuration files before running and don't just copy and paste what you see here. This information is provided AS IS and there are plenty of resources available online if you run into problems.
This information has been pulled from various sources and is essentially notes on how to setup an NGINX reverse proxy. This is not a complete how-to guide and you are assumed to already know how to setup/configure/use nginx, docker, openssl, certbot (let's encrypt), etc.
Stand alone
This config is for a stand-alone install of NGINX on a VM. You can uncomment the lines that start with ssl to provide your own cert, or instlal Let
The v1 and v2 versions are listed as they depend entirely on what version of NGINX is being used.
v1
# Upstreams
upstream backend {
server 127.0.0.1:3000;
}
# HTTPS Server
server {
# listen 443;
server_name changeme.local;
# You can increase the limit if your need to.
client_max_body_size 200M;
error_log /var/log/nginx/access.log;
# uncomment and update if using an SSL cert obtained from elsewhere
# ssl on;
# ssl_certificate /etc/nginx/certificate.crt;
# ssl_certificate_key /etc/nginx/certificate.key;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # don’t use SSLv3 ref: POODLE
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
}
}
v2
events {
worker_connections 4096; ## Default: 1024
}
# HTTPS Server
http {
# Upstreams
upstream backend {
server 127.0.0.1:8181;
}
server {
# listen 443;
server_name <fqdn of server>;
# You can increase the limit if your need to.
client_max_body_size 200M;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# uncomment and update if using an SSL cert obtained from elsewhere
# ssl on;
# ssl_certificate /etc/nginx/certificate.crt;
# ssl_certificate_key /etc/nginx/certificate.key;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # don’t use SSLv3 ref: POODLE
gzip on;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
}
}
}
Let's Encrypt
- Install the Let's Encrypt Certbot and NGINX plugin to use Let's Encrypt SSL certs automatically managed by Certbot:
apt install -y certbot python3-certbot-nginx
- Request a cert for your domain to be used by NGINX
certbot -d <domain> --nginx
Docker
Configuration
- Create the /srv/nginx-proxy directory
- Copy the following to /srv/nginx-proxy/docker-compose.yml:
version: "3"
services:
proxy:
image: jwilder/nginx-proxy:alpine
restart: always
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:ro
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
- ./conf.d:/etc/nginx/conf.d
environment:
- DEFAULT_HOST=demo.example.com
ports:
- "443:443"
- "80:80"
- Copy the following to /srv/nginx-proxy/docker-compose.override.yml:
proxyapp:
environment:
- VIRTUAL_HOST=demo.example.com
- VIRTUAL_PORT=8080
uspsapp:
environment:
- VIRTUAL_HOST=demo.example.com
- VIRTUAL_PORT=8080
SSL Certificates
- Create reg.conf in /srv/nginx/certs:
[req]
default_bits = 2048
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = Some Country
ST = Some State
L = Some City/Location
O = Who are you?
CN = <fqdn of server>
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = <fqdn of server>
DNS.2 = <hostname of server without domain>
IP.1 = <IP of server>
- Generate a new CSR and print key to console (save key in <fqdn>.key file:
openssl req -config reg.conf -newkey rsa:2048 -sha256 -nodes -days 730 -out <hostname>.csr -outform pem
- Send the CSR to a signing authority or self sign it:
# openssl x509 -req -sha256 -days 3650 -in demo.example.com.csr -signkey demo.example.com.key -out demo.example.com.crt
Note: Make sure the certs are in /srv/nginx-proxy/certs
- Download the full chain and individual certificate
- Make sure full chain is in correct format with:
openssl pkcs7 -print_certs -in chain.p7b -out chain.cer
- Correct chain file will look simliar to:
subject=C = Some Country, ST = Some State, L = Some City, O = Some Org, CN = <fqdn of server>
issuer=DC = <Domain>, DC = <Domain>, CN = <CA Issuing Authority>
-----BEGIN CERTIFICATE-----
<cert>
-----END CERTIFICATE-----
subject=DC = <Domain>, DC = <Domain>, CN = <CA Server>
issuer=DC = <Domain>, DC = <Domain>, CN = <CA Issuing Authority>
-----BEGIN CERTIFICATE-----
<snip>
-----END CERTIFICATE-----
subject=DC = <Domain>, DC = <Domain>, CN = <CA Server>
issuer=CN = <Root CA>
-----BEGIN CERTIFICATE-----
<snip>
-----END CERTIFICATE-----
subject=CN = <CA Server>
issuer=CN = <Root CA>
-----BEGIN CERTIFICATE-----
<snip>
-----END CERTIFICATE-----
- Certificate files need to match the VIRTUAL_HOST of the container as follows:
root@server:/srv/nginx-proxy/certs# ls -alh
total 48K
drwxr-xr-x 2 root root 4.0K Sep 21 22:47 .
drwxr-xr-x 6 root root 4.0K Sep 21 22:49 ..
-rw-r--r-- 1 root root 9.9K Sep 21 22:45 chain.p7b
-rw-r--r-- 1 root root 426 Sep 21 22:32 reg.conf
-rw-r--r-- 1 root root 1.2K Sep 21 22:36 <hostname>.csr
-rw-r--r-- 1 root root 8.0K Sep 21 22:46 <fqdn>.chain.pem <-- used by NGINX
-rw-r--r-- 1 root root 2.5K Sep 21 22:45 <fqdn>.crt <-- used by NGINX
-rw-r--r-- 1 root root 424 Sep 21 22:27 <fqdn>.dhparam.pem <-- used by NGINX
-rw-r--r-- 1 root root 1.7K Sep 21 22:37 <fqdn>.key <-- used by NGINX
- Generate dhparam with:
openssl dhparam -out /etc/nginx/ssl/dhparam-2048.pem 2048
- Configure NGINX to listen on port 443 by adding to the ports section of the /srv/nginx-proxy/docker-compose.yml file
- "443:443"
Lets Encrypt
- Copy the following to /srv/nginx-proxy/docker-compose.yml:
version: "3"
services:
proxy:
image: jwilder/nginx-proxy:alpine
restart: always
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:ro
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
- ./conf.d:/etc/nginx/conf.d
environment:
- DEFAULT_HOST=demo.example.com
ports:
- "443:443"
- "80:80"
labels:
- "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"
le:
image: jrcs/letsencrypt-nginx-proxy-companion
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/etc/nginx/certs:rw
- ./vhost.d:/etc/nginx/vhost.d:rw
- ./html:/usr/share/nginx/html:rw
environment:
- NGINX_PROXY_CONTAINER=proxy_proxy_1
- For each app you want to use Let's Encrypt SSL on, update /srv/nginx-proxy/docker-compose.override.yml:
proxyapp:
environments:
- VIRTUAL_HOST=demo.example.com
- VIRTUAL_PORT=8080
- LETSENCRYPT_HOST=demo.example.com
- LETSENCRYPT_EMAIL=hostmaster@example.com
Timeout
To adjust the timeout of NGINX Proxy, add the following to /srv/nginx-proxy/docker-compose.yml under volumes:
- ./conf.d:/etc/nginx/conf.d
- Copy the following to /srv/nginx-proxy/conf.d/proxy-serttings.conf:
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 90m;
send_timeout 300;
If issues are due to upload size, add the following additional line to the config file above:
client_max_body_size 5000m;
Note: Adjust values as needed.
Compression
- Add the following to /srv/nginx/proxy/conf.d/compression.conf:
# ----------------------------------------------------------------------
# | Compression |
# ----------------------------------------------------------------------
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html
# Enable gzip compression.
# Default: off
gzip on;
# Compression level (1-9).
# 5 is a perfect compromise between size and CPU usage, offering about 75%
# reduction for most ASCII files (almost identical to level 9).
# Default: 1
gzip_comp_level 5;
# Don't compress anything that's already small and unlikely to shrink much if at
# all (the default is 20 bytes, which is bad as that usually leads to larger
# files after gzipping).
# Default: 20
gzip_min_length 256;
# Compress data even for clients that are connecting to us via proxies,
# identified by the "Via" header (required for CloudFront).
# Default: off
gzip_proxied any;
# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client's Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
# Default: off
gzip_vary on;
# Compress all output labeled with one of the following MIME-types.
# `text/html` is always compressed by gzip module.
# Default: text/html
gzip_types
application/atom+xml
application/geo+json
application/javascript
application/x-javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/vnd.ms-fontobject
application/wasm
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/eot
font/otf
font/ttf
image/bmp
image/svg+xml
text/cache-manifest
text/calendar
text/css
text/javascript
text/markdown
text/plain
text/xml
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
Miscellaneous
ACMEv1/ACMEv2 error
- LetsEncrypt no longer supports ACMEv1 for certificate management. If your site stops automatically renewing/generating certificates, this may appear in the logs:
docker-compose logs --tail=50 le
...
le_1 | 2020-01-09 11:48:43,395:INFO:simp_le:1382: Generating new account key
le_1 | ACME server returned an error: urn:acme:error:unauthorized :: The client lacks sufficient authorization ::
Account creation on ACMEv1 is disabled. Please upgrade your ACME client to a version that supports ACMEv2 / RFC 8555.
See https://community.letsencrypt.org/t/end-of-life-plan-for-acmev1/88430 for details.
- To resolve this, make sure you have the latest images. See https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion
- To check if it successful, go to the certs/accounts directory. You will see something like this if it is using ACMEv2 - in this case our proxy docker-compose.yml is in /data/proxy:
/data/proxy/certs/accounts# ls
acme-v02.api.letsencrypt.org
Checking site configuration
- Check http/2 and ALPN configuration: https://tools.keycdn.com/http2-test
- Check SSL, Chain, and Security: https://www.ssllabs.com/ssltest/
Force Lets Encrypt certificate renewal
- Force certificate renewal for all:
docker exec name_of_lets_encrypt_container/app/force_renew
Example:
docker exec proxy_le_1 /app/force_renew
Get Lets Encrypt certificate status
- Get certificate status - note in this case, I did a force renew on 3/30, so 90 days is 6/28.
docker exec name_of_lets_encrypt_container/app/cert_status
Example:
docker exec proxy_le_1 /app/cert_status
##### Certificate status #####
/etc/nginx/certs/server/fullchain.pem: no corresponding chain.pem file, unable to verify certificate
Certificate was issued by Let's Encrypt Authority X3
Certificate is valid until Jun 28 13:11:46 2020 GMT
...