diff --git a/README.md b/README.md index 68d0953..2ac7a99 100644 --- a/README.md +++ b/README.md @@ -175,10 +175,25 @@ Default value : Use this kind of environment variable to define custom error page depending on the HTTP error code. Replace XXX with HTTP code. For example : `ERROR_404=/404.html` means the /404.html page will be displayed when 404 code is generated. The path is relative to the root web folder. -`PROXY_REAL_IP` -Values : *yes* | *no* -Default value : *no* -Use this kind of environment variable to define whether you're using Nginx inside another proxy, this means you will see "X-Forwarded-For" instead of regular "Remote-Addr" IPs inside your logs. Modsecurity will also then work correctly. +`PROXY_REAL_IP` +Values : *yes* | *no* +Default value : *no* +Set this environment variable to *yes* if you're using bunkerized-nginx behind a reverse proxy. This means you will see the real client address instead of the proxy one inside your logs. Modsecurity, fail2ban and others security tools will also then work correctly. + +`PROXY_REAL_IP_FROM` +Values : *\* +Default value : *192.168.0.0/16 172.16.0.0/12 10.0.0.0/8* +When `PROXY_REAL_IP` is set to *yes*, lets you define the trusted IPs/networks allowed to send the correct client address. + +`PROXY_REAL_IP_HEADER` +Values : *X-Forwarded-For* | *X-Real-IP* | *custom header* +Default value : *X-Forwarded-For* +When `PROXY_REAL_IP` is set to *yes*, lets you define the header that contains the real client IP address. + +`PROXY_REAL_IP_RECURSIVE` +Values : *on* | *off* +Default value : *on* +When `PROXY_REAL_IP` is set to *yes*, setting this to *on* avoid spoofing attacks using the header defined in `PROXY_REAL_IP_HEADER`. ## HTTPS `AUTO_LETS_ENCRYPT` @@ -203,7 +218,7 @@ Values : *yes* | *no* Default value : *yes* If set to yes, nginx will use HTTP2 protocol when HTTPS is enabled. -`USE_CUSTOM_HTTPS` +`USE_CUSTOM_HTTPS` Values : *yes* | *no* Default value : *no* If set to yes, HTTPS will be enabled with certificate/key of your choice. @@ -218,51 +233,51 @@ Values : *\* Default value : Full path of the key file to use when `USE_CUSTOM_HTTPS` is set to yes. -`GENERATE_SELF_SIGNED_SSL` -Values : *yes* | *no* -Default value : *no* -If set to yes, HTTPS will be enabled with a container generated self signed SSL. +`GENERATE_SELF_SIGNED_SSL` +Values : *yes* | *no* +Default value : *no* +If set to yes, HTTPS will be enabled with a container generated self-signed certificate. -`SELF_SIGNED_SSL_EXPIRY` -Values : *integer* -Default value : *365* (1 year) -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_EXPIRY` +Values : *integer* +Default value : *365* (1 year) +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the expiry date for the self generated certificate. -`SELF_SIGNED_SSL_COUNTRY` -Values : *text* -Default value : *Switzerland* -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_COUNTRY` +Values : *text* +Default value : *Switzerland* +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the country for the self generated certificate. -`SELF_SIGNED_SSL_STATE` -Values : *text* -Default value : *Switzerland* -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_STATE` +Values : *text* +Default value : *Switzerland* +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the state for the self generated certificate. -`SELF_SIGNED_SSL_CITY` -Values : *text* -Default value : *Bern* -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_CITY` +Values : *text* +Default value : *Bern* +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the city for the self generated certificate. -`SELF_SIGNED_SSL_ORG` -Values : *text* -Default value : *AcmeInc* -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_ORG` +Values : *text* +Default value : *AcmeInc* +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the organisation name for the self generated certificate. -`SELF_SIGNED_SSL_OU` -Values : *text* -Default value : *IT* -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_OU` +Values : *text* +Default value : *IT* +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the organisitional unit for the self generated certificate. -`SELF_SIGNED_SSL_CN` -Values : *text* -Default value : *bunkerity-nginx* -Needs "GENERATE_SELF_SIGNED_SSL" to work. +`SELF_SIGNED_SSL_CN` +Values : *text* +Default value : *bunkerity-nginx* +Needs `GENERATE_SELF_SIGNED_SSL` to work. Sets the CN server name for the self generated certificate. ## ModSecurity diff --git a/confs/https.conf b/confs/https.conf new file mode 100644 index 0000000..6a094f7 --- /dev/null +++ b/confs/https.conf @@ -0,0 +1,7 @@ +listen 0.0.0.0:443 ssl %HTTP2%; +ssl_certificate %HTTPS_CERT%; +ssl_certificate_key %HTTPS_KEY%; +ssl_protocols TLSv1.3; +ssl_prefer_server_ciphers off; +ssl_session_tickets off; +%STRICT_TRANSPORT_SECURITY% diff --git a/confs/nginx.conf b/confs/nginx.conf index fcdb3ae..a3c528f 100644 --- a/confs/nginx.conf +++ b/confs/nginx.conf @@ -61,9 +61,11 @@ http { # enable/disable sending nginx version server_tokens %SERVER_TOKENS%; - # write logs to local syslogd + # get real IP address if behind a reverse proxy %PROXY_REAL_IP% - access_log syslog:server=unix:/dev/log,nohostname,facility=local0 %LOG_TYPE%; + + # write logs to local syslogd + access_log syslog:server=unix:/dev/log,nohostname,facility=local0 combined; error_log syslog:server=unix:/dev/log,nohostname,facility=local0,severity=warn; # lua path diff --git a/confs/proxy-real-ip.conf b/confs/proxy-real-ip.conf index bc6b799..4d972c4 100644 --- a/confs/proxy-real-ip.conf +++ b/confs/proxy-real-ip.conf @@ -1,3 +1,4 @@ -log_format proxy '$http_x_real_ip - $remote_user [$time_local] ' - '"$request" $status $body_bytes_sent ' - '"$http_referer" "$http_user_agent"'; +%PROXY_REAL_IP_FROM% +real_ip_header %PROXY_REAL_IP_HEADER%; +real_ip_recursive %PROXY_REAL_IP_RECURSIVE%; + diff --git a/confs/server.conf b/confs/server.conf index e70eec6..e7e18be 100644 --- a/confs/server.conf +++ b/confs/server.conf @@ -1,8 +1,7 @@ server { include /server-confs/*.conf; %LISTEN_HTTP% - %AUTO_LETS_ENCRYPT% - %CUSTOM_HTTPS% + %USE_HTTPS% %REDIRECT_HTTP_TO_HTTPS% server_name %SERVER_NAME%; %DISABLE_DEFAULT_SERVER% diff --git a/entrypoint.sh b/entrypoint.sh index 39ca02b..a8dc889 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -132,6 +132,9 @@ LIMIT_REQ_RATE="${LIMIT_REQ_RATE-20r/s}" LIMIT_REQ_BURST="${LIMIT_REQ_BURST-40}" LIMIT_REQ_CACHE="${LIMIT_REQ_CACHE-10m}" PROXY_REAL_IP="${PROXY_REAL_IP-no}" +PROXY_REAL_IP_FROM="${PROXY_REAL_IP_FROM-192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}" +PROXY_REAL_IP_HEADER="${PROXY_REAL_IP_HEADER-X-Forwarded-For}" +PROXY_REAL_IP_RECURSIVE="${PROXY_REAL_IP_RECURSIVE-on}" GENERATE_SELF_SIGNED_SSL="${GENERATE_SELF_SIGNED_SSL-no"}" SELF_SIGNED_SSL_EXPIRY="${SELF_SIGNED_SSL_EXPIRY-365}" SELF_SIGNED_SSL_COUNTRY="${SELF_SIGNED_SSL_COUNTRY-Switzerland}" @@ -283,59 +286,45 @@ if [ "$BLOCK_ABUSERS" = "yes" ] ; then else replace_in_file "/etc/nginx/server.conf" "%BLOCK_ABUSERS%" "" fi -if [ "$AUTO_LETS_ENCRYPT" = "yes" ] && [ "$USE_CUSTOM_HTTPS" = "no" ]; then - FIRST_SERVER_NAME=$(echo "$SERVER_NAME" | cut -d " " -f 1) - DOMAINS_LETS_ENCRYPT=$(echo "$SERVER_NAME" | sed "s/ /,/g") - EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$FIRST_SERVER_NAME}" - - replace_in_file "/etc/nginx/server.conf" "%AUTO_LETS_ENCRYPT%" "include /etc/nginx/auto-lets-encrypt.conf;" +# HTTPS config +if [ "$AUTO_LETS_ENCRYPT" = "yes" ] || [ "$USE_CUSTOM_HTTPS" = "yes" ] || [ "$GENERATE_SELF_SIGNED_SSL" = "yes" ] ; then + replace_in_file "/etc/nginx/server.conf" "%USE_HTTPS%" "include /etc/nginx/https.conf;" if [ "$HTTP2" = "yes" ] ; then - replace_in_file "/etc/nginx/auto-lets-encrypt.conf" "%HTTP2%" "http2" + replace_in_file "/etc/nginx/https.conf" "%HTTP2%" "http2" else - replace_in_file "/etc/nginx/auto-lets-encrypt.conf" "%HTTP2%" "" - fi - replace_in_file "/etc/nginx/auto-lets-encrypt.conf" "%FIRST_SERVER_NAME%" "$FIRST_SERVER_NAME" - if [ "$STRICT_TRANSPORT_SECURITY" != "" ] ; then - replace_in_file "/etc/nginx/auto-lets-encrypt.conf" "%STRICT_TRANSPORT_SECURITY%" "more_set_headers 'Strict-Transport-Security: $STRICT_TRANSPORT_SECURITY';" - else - replace_in_file "/etc/nginx/auto-lets-encrypt.conf" "%STRICT_TRANSPORT_SECURITY%" "" - fi - if [ -f /etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem ] ; then - /opt/scripts/certbot-renew.sh - else - certbot certonly --standalone -n --preferred-challenges http -d "$DOMAINS_LETS_ENCRYPT" --email "$EMAIL_LETS_ENCRYPT" --agree-tos - fi - echo "0 0 * * * /opt/scripts/certbot-renew.sh" >> /etc/crontabs/root -else - replace_in_file "/etc/nginx/server.conf" "%AUTO_LETS_ENCRYPT%" "" -fi -if [ "$USE_CUSTOM_HTTPS" = "yes" ] && [ "$AUTO_LETS_ENCRYPT" = "no" ]; then - replace_in_file "/etc/nginx/server.conf" "%CUSTOM_HTTPS%" "include /etc/nginx/custom-https.conf;" - if [ "$HTTP2" = "yes" ] ; then - replace_in_file "/etc/nginx/custom-https.conf" "%HTTP2%" "http2" - else - replace_in_file "/etc/nginx/custom-https.conf" "%HTTP2%" "" + replace_in_file "/etc/nginx/https.conf" "%HTTP2%" "" fi if [ "$STRICT_TRANSPORT_SECURITY" != "" ] ; then - replace_in_file "/etc/nginx/custom-https.conf" "%STRICT_TRANSPORT_SECURITY%" "more_set_headers 'Strict-Transport-Security: $STRICT_TRANSPORT_SECURITY';" + replace_in_file "/etc/nginx/https.conf" "%STRICT_TRANSPORT_SECURITY%" "more_set_headers 'Strict-Transport-Security: $STRICT_TRANSPORT_SECURITY';" else - replace_in_file "/etc/nginx/custom-https.conf" "%STRICT_TRANSPORT_SECURITY%" "" + replace_in_file "/etc/nginx/https.conf" "%STRICT_TRANSPORT_SECURITY%" "" fi - replace_in_file "/etc/nginx/custom-https.conf" "%HTTPS_CUSTOM_CERT%" "$HTTPS_CUSTOM_CERT" - replace_in_file "/etc/nginx/custom-https.conf" "%HTTPS_CUSTOM_KEY%" "$HTTPS_CUSTOM_KEY" - if [ "$GENERATE_SELF_SIGNED_SSL" = "yes" ] ; then + if [ "$AUTO_LETS_ENCRYPT" = "yes" ] ; then + FIRST_SERVER_NAME=$(echo "$SERVER_NAME" | cut -d " " -f 1) + DOMAINS_LETS_ENCRYPT=$(echo "$SERVER_NAME" | sed "s/ /,/g") + EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$FIRST_SERVER_NAME}" + replace_in_file "/etc/nginx/https.conf" "%HTTPS_CERT%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem" + replace_in_file "/etc/nginx/https.conf" "%HTTPS_KEY%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/privkey.pem" + if [ -f /etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem ] ; then + /opt/scripts/certbot-renew.sh + else + certbot certonly --standalone -n --preferred-challenges http -d "$DOMAINS_LETS_ENCRYPT" --email "$EMAIL_LETS_ENCRYPT" --agree-tos + fi + echo "0 0 * * * /opt/scripts/certbot-renew.sh" >> /etc/crontabs/root + elif [ "$USE_CUSTOM_HTTPS" = "yes" ] ; then + replace_in_file "/etc/nginx/https.conf" "%HTTPS_CERT%" "$CUSTOM_HTTPS_CERT" + replace_in_file "/etc/nginx/https.conf" "%HTTPS_KEY%" "$CUSTOM_HTTPS_KEY" + elif [ "$GENERATE_SELF_SIGNED_SSL" = "yes" ] ; then mkdir /etc/nginx/self-signed-ssl/ openssl req -nodes -x509 -newkey rsa:4096 -keyout /etc/nginx/self-signed-ssl/key.pem -out /etc/nginx/self-signed-ssl/cert.pem -days $SELF_SIGNED_SSL_EXPIRY -subj "/C=$SELF_SIGNED_SSL_COUNTRY/ST=$SELF_SIGNED_SSL_STATE/L=$SELF_SIGNED_SSL_CITY/O=$SELF_SIGNED_SSL_ORG/OU=$SELF_SIGNED_SSL_OU/CN=$SELF_SIGNED_SSL_CN" - replace_in_file "/etc/nginx/custom-https.conf" "%HTTPS_CUSTOM_CERT%" "/etc/nginx/self-signed-ssl/cert.pem" - replace_in_file "/etc/nginx/custom-https.conf" "%HTTPS_CUSTOM_KEY%" "/etc/nginx/self-signed-ssl/key.pem" - else - replace_in_file "/etc/nginx/custom-https.conf" "%HTTPS_CUSTOM_CERT%" "$HTTPS_CUSTOM_CERT" - replace_in_file "/etc/nginx/custom-https.conf" "%HTTPS_CUSTOM_KEY%" "$HTTPS_CUSTOM_KEY" - fi + replace_in_file "/etc/nginx/https.conf" "%HTTPS_CERT%" "/etc/nginx/self-signed-ssl/cert.pem" + replace_in_file "/etc/nginx/https.conf" "%HTTPS_KEY%" "/etc/nginx/self-signed-ssl/key.pem" + fi else - replace_in_file "/etc/nginx/server.conf" "%CUSTOM_HTTPS%" "" + replace_in_file "/etc/nginx/server.conf" "%USE_HTTPS%" "" fi + if [ "$LISTEN_HTTP" = "yes" ] ; then replace_in_file "/etc/nginx/server.conf" "%LISTEN_HTTP%" "listen 0.0.0.0:80;" else @@ -372,11 +361,16 @@ else replace_in_file "/etc/nginx/nginx.conf" "%USE_MODSECURITY%" "" fi if [ "$PROXY_REAL_IP" = "yes" ] ; then - replace_in_file "/etc/nginx/server.conf" "%PROXY_REAL_IP%" "include /etc/nginx/proxy-real-ip.conf;" - replace_in_file "/etc/nginx/server.conf" "%LOG_TYPE%" "proxy" + replace_in_file "/etc/nginx/server.conf" "%PROXY_REAL_IP%" "include /etc/nginx/proxy-real-ip.conf;" + froms="" + for from in $PROXY_REAL_IP_FROM ; do + froms="${froms}set_real_ip_from ${from};\n" + done + replace_in_file "/etc/nginx/proxy-real-ip.conf" "%PROXY_REAL_IP_FROM%" "$froms" + replace_in_file "/etc/nginx/proxy-real-ip.conf" "%PROXY_REAL_IP_HEADER%" "$PROXY_REAL_IP_HEADER" + replace_in_file "/etc/nginx/proxy-real-ip.conf" "%PROXY_REAL_IP_RECURSIVE%" "$PROXY_REAL_IP_RECURSIVE" else - replace_in_file "/etc/nginx/server.conf" "%PROXY_REAL_IP%" "" - replace_in_file "/etc/nginx/server.conf" "%LOG_TYPE%" "combined" + replace_in_file "/etc/nginx/server.conf" "%PROXY_REAL_IP%" "" fi