dynamic reload of nginx by sending SIGHUP

This commit is contained in:
bunkerity 2020-12-09 17:00:09 +01:00
parent 15e74e4860
commit 92569679b6
No known key found for this signature in database
GPG Key ID: 654FFF51CEF7CC47
9 changed files with 144 additions and 58 deletions

View File

@ -1,11 +1,15 @@
FROM alpine FROM alpine
RUN apk add py3-pip && \ RUN apk add py3-pip apache2-utils bash && \
pip3 install docker pip3 install docker && \
mkdir /opt/entrypoint && \
mkdir -p /opt/confs/site
COPY *.py /opt/ COPY confs/site/ /opt/confs/site
RUN chmod +x /opt/entrypoint.py COPY entrypoint/* /opt/entrypoint/
COPY autoconf/* /opt/entrypoint/
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh
VOLUME /etc/nginx VOLUME /etc/nginx
ENTRYPOINT ["/opt/entrypoint.py"] ENTRYPOINT ["/opt/entrypoint/entrypoint.py"]

View File

@ -1,13 +1,13 @@
#!/usr/bin/python3 #!/usr/bin/python3
import utils import utils
import subprocess, shutil, os import subprocess, shutil, os, traceback
def generate(instances, vars) : def generate(instances, vars) :
try : try :
# Get env vars from bunkerized-nginx instances # Get env vars from bunkerized-nginx instances
vars_instances = {} vars_instances = {}
for instance_id, instance in instances : for instance_id, instance in instances.items() :
for var_value in instance.attrs["Config"]["Env"] : for var_value in instance.attrs["Config"]["Env"] :
var = var_value.split("=")[0] var = var_value.split("=")[0]
value = var_value.replace(var + "=", "", 1) value = var_value.replace(var + "=", "", 1)
@ -16,10 +16,11 @@ def generate(instances, vars) :
vars_defaults.update(vars_instances) vars_defaults.update(vars_instances)
vars_defaults.update(vars) vars_defaults.update(vars)
# Call site-config.sh to generate the config # Call site-config.sh to generate the config
proc = subprocess.run(["/opt/site-config.sh", vars["SERVER_NAME"]], env=vars_defaults, capture_output=True) proc = subprocess.run(["/opt/entrypoint/site-config.sh", vars["SERVER_NAME"]], env=vars_defaults, capture_output=True)
if proc.returncode == 0 : if proc.returncode == 0 :
return True return True
except Exception as e : except Exception as e :
traceback.print_exc()
utils.log("[!] Error while generating config : " + str(e)) utils.log("[!] Error while generating config : " + str(e))
return False return False
@ -34,11 +35,11 @@ def activate(instances, vars) :
utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}") utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}")
# Send SIGHUP to all running instances # Send SIGHUP to all running instances
for instance_id, instance in instances : for instance_id, instance in instances.items() :
if instance.status == "running" : if instance.status == "running" :
try : try :
instance.kill("SIGHUP") instance.kill("SIGHUP")
utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id)
except docker.errors.APIError as e : except docker.errors.APIError as e :
utils.log("[!] Docker error while sending SIGHUP signal : " + str(e)) utils.log("[!] Docker error while sending SIGHUP signal : " + str(e))
return True return True
@ -57,11 +58,11 @@ def deactivate(instances, vars) :
utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "") utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "")
# Send SIGHUP to all running instances # Send SIGHUP to all running instances
for instance_id, instance in instances : for instance_id, instance in instances.items() :
if instance.status == "running" : if instance.status == "running" :
try : try :
instance.kill("SIGHUP") instance.kill("SIGHUP")
utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id)
except docker.errors.APIError as e : except docker.errors.APIError as e :
utils.log("[!] Docker error while sending SIGHUP signal : " + str(e)) utils.log("[!] Docker error while sending SIGHUP signal : " + str(e))
return True return True

View File

@ -32,23 +32,26 @@ def process(container, event) :
else : else :
utils.log("[!] Can't generate config for " + vars["SERVER_NAME"]) utils.log("[!] Can't generate config for " + vars["SERVER_NAME"])
elif event == "start" : elif event == "start" :
containers[container.id].reload() if container.id in containers :
if config.activate(instances, vars) : containers[container.id].reload()
utils.log("[*] Activated config for " + vars["SERVER_NAME"]) if config.activate(instances, vars) :
else : utils.log("[*] Activated config for " + vars["SERVER_NAME"])
utils.log("[!] Can't activate config for " + vars["SERVER_NAME"]) else :
utils.log("[!] Can't activate config for " + vars["SERVER_NAME"])
elif event == "die" : elif event == "die" :
containers[container.id].reload() if container.id in containers :
if config.deactivate(instances, vars) : containers[container.id].reload()
utils.log("[*] Deactivated config for " + vars["SERVER_NAME"]) if config.deactivate(instances, vars) :
else : utils.log("[*] Deactivated config for " + vars["SERVER_NAME"])
utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"]) else :
utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"])
elif event == "destroy" : elif event == "destroy" :
del containers[container.id] if container.id in containers :
if config.remove(vars) : del containers[container.id]
utils.log("[*] Removed config for " + vars["SERVER_NAME"]) if config.remove(vars) :
else : utils.log("[*] Removed config for " + vars["SERVER_NAME"])
utils.log("[!] Can't remove config for " + vars["SERVER_NAME"]) else :
utils.log("[!] Can't remove config for " + vars["SERVER_NAME"])
# Connect to the endpoint # Connect to the endpoint
endpoint = "/var/run/docker.sock" endpoint = "/var/run/docker.sock"

25
confs/site/fastcgi.conf Normal file
View File

@ -0,0 +1,25 @@
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;

View File

@ -30,6 +30,9 @@ trap "trap_exit" TERM INT
# trap SIGHUP # trap SIGHUP
function trap_reload() { function trap_reload() {
echo "[*] Catched reload operation" echo "[*] Catched reload operation"
if [ "$MULTISITE" = "yes" ] ; then
/opt/entrypoint/multisite-config.sh
fi
if [ -f /tmp/nginx.pid ] ; then if [ -f /tmp/nginx.pid ] ; then
echo "[*] Reloading nginx ..." echo "[*] Reloading nginx ..."
/usr/sbin/nginx -s reload /usr/sbin/nginx -s reload
@ -53,6 +56,7 @@ if [ ! -f "/opt/installed" ] ; then
/opt/entrypoint/site-config.sh "$server" /opt/entrypoint/site-config.sh "$server"
echo "[*] Multi site - $server configuration done" echo "[*] Multi site - $server configuration done"
done done
/opt/entrypoint/multisite-config.sh
else else
/opt/entrypoint/site-config.sh /opt/entrypoint/site-config.sh
echo "[*] Single site - $SERVER_NAME configuration done" echo "[*] Single site - $SERVER_NAME configuration done"
@ -67,13 +71,6 @@ chown -R root:nginx /etc/nginx/
chmod -R 740 /etc/nginx/ chmod -R 740 /etc/nginx/
find /etc/nginx -type d -exec chmod 750 {} \; find /etc/nginx -type d -exec chmod 750 {} \;
# fix let's encrypt rights
if [ "$AUTO_LETS_ENCRYPT" = "yes" ] ; then
chown -R root:nginx /etc/letsencrypt
chmod -R 740 /etc/letsencrypt
find /etc/letsencrypt -type d -exec chmod 750 {} \;
fi
# start rsyslogd # start rsyslogd
rsyslogd rsyslogd

View File

@ -0,0 +1,42 @@
#!/bin/sh
# load default values
. /opt/entrypoint/defaults.sh
# load some functions
. /opt/entrypoint/utils.sh
# fix nginx configs rights (and modules through the symlink)
chown -R root:nginx /etc/nginx/
chmod -R 740 /etc/nginx/
find /etc/nginx -type d -exec chmod 750 {} \;
if [ "$MULTISITE" = "yes" ] ; then
servers=$(find /etc/nginx -name "server.conf" | cut -d '/' -f 4)
for server in $servers ; do
SERVER_PREFIX="/etc/nginx/${server}/"
if grep "/etc/letsencrypt/live" ${SERVER_PREFIX}https.conf > /dev/null && [ ! -f /etc/letsencrypt/live/${server}/fullchain.pem ] ; then
/opt/scripts/certbot-new.sh "$1" "$(cat ${SERVER_PREFIX}email-lets-encrypt.txt)"
fi
if grep "modsecurity.conf" ${SERVER_PREFIX}server.conf > /dev/null ; then
modsec_custom=""
if ls /modsec-confs/*.conf > /dev/null 2>&1 ; then
modsec_custom="include /modsec-confs/*.conf\n"
fi
if ls /modsec-confs/${1}/*.conf > /dev/null 2>&1 ; then
modsec_custom="${modsec_custom}include /modsec-confs/${server}/*.conf\n"
fi
replace_in_file "${SERVER_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_RULES%" "$modsec_custom"
if grep "owasp-crs.conf" ${SERVER_PREFIX}modsecurity-rules.conf > /dev/null ; then
modsec_crs_custom=""
if ls /modsec-crs-confs/*.conf > /dev/null 2>&1 ; then
modsec_crs_custom="include /modsec-crs-confs/*.conf\n"
fi
if ls /modsec-crs-confs/${1}/*.conf > /dev/null 2>&1 ; then
modsec_crs_custom="${modsec_custom}include /modsec-crs-confs/${server}/*.conf\n"
fi
fi
replace_in_file "${SERVER_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" "$modsec_crs_custom"
fi
done
fi

View File

@ -137,9 +137,6 @@ if [ "$REMOTE_PHP" != "" ] ; then
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" "include ${NGINX_PREFIX}php.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" "include ${NGINX_PREFIX}php.conf;"
replace_in_file "${NGINX_PREFIX}server.conf" "%FASTCGI_PATH%" "include ${NGINX_PREFIX}fastcgi.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%FASTCGI_PATH%" "include ${NGINX_PREFIX}fastcgi.conf;"
replace_in_file "${NGINX_PREFIX}php.conf" "%REMOTE_PHP%" "$REMOTE_PHP" replace_in_file "${NGINX_PREFIX}php.conf" "%REMOTE_PHP%" "$REMOTE_PHP"
if [ "$MULTISITE" = "yes" ] ; then
cp /etc/nginx/fastcgi.conf ${NGINX_PREFIX}fastcgi.conf && chown root:nginx ${NGINX_PREFIX}fastcgi.conf
fi
replace_in_file "${NGINX_PREFIX}fastcgi.conf" "\$document_root" "${REMOTE_PHP_PATH}/" replace_in_file "${NGINX_PREFIX}fastcgi.conf" "\$document_root" "${REMOTE_PHP_PATH}/"
else else
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" "" replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" ""
@ -322,11 +319,8 @@ if [ "$AUTO_LETS_ENCRYPT" = "yes" ] || [ "$USE_CUSTOM_HTTPS" = "yes" ] || [ "$GE
FIRST_SERVER_NAME=$(echo "$SERVER_NAME" | cut -d " " -f 1) FIRST_SERVER_NAME=$(echo "$SERVER_NAME" | cut -d " " -f 1)
else else
FIRST_SERVER_NAME="$1" FIRST_SERVER_NAME="$1"
if [ ! -f /etc/letsencrypt/live/${1}/fullchain.pem ] ; then EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$1}"
echo "[*] Performing Let's Encrypt challenge for $1 ..." echo -n "$EMAIL_LETS_ENCRYPT" > ${NGINX_PREFIX}email-lets-encrypt.txt
EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$1}"
/opt/scripts/certbot-new.sh "$1" "$EMAIL_LETS_ENCRYPT"
fi
fi fi
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem" replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem"
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/privkey.pem" replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/privkey.pem"
@ -362,24 +356,22 @@ fi
if [ "$USE_MODSECURITY" = "yes" ] ; then if [ "$USE_MODSECURITY" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}modsecurity.conf" "%MODSEC_RULES_FILE%" "${NGINX_PREFIX}/modsecurity-rules.conf" replace_in_file "${NGINX_PREFIX}modsecurity.conf" "%MODSEC_RULES_FILE%" "${NGINX_PREFIX}/modsecurity-rules.conf"
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_MODSECURITY%" "include ${NGINX_PREFIX}modsecurity.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%USE_MODSECURITY%" "include ${NGINX_PREFIX}modsecurity.conf;"
modsec_custom="" if [ "$MULTISITE" != "yes" ] ; then
if ls /modsec-confs/*.conf > /dev/null 2>&1 ; then modsec_custom=""
modsec_custom="include /modsec-confs/*.conf\n" if ls /modsec-confs/*.conf > /dev/null 2>&1 ; then
modsec_custom="include /modsec-confs/*.conf\n"
fi
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_RULES%" "$modsec_custom"
fi fi
if [ "$MULTISITE" = "yes" ] && ls /modsec-confs/${1}/*.conf > /dev/null 2>&1 ; then
modsec_custom="${modsec_custom}include /modsec-confs/${1}/*.conf\n"
fi
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_RULES%" "$modsec_custom"
if [ "$USE_MODSECURITY_CRS" = "yes" ] ; then if [ "$USE_MODSECURITY_CRS" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" "include /etc/nginx/owasp-crs.conf" replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" "include /etc/nginx/owasp-crs.conf"
modsec_crs_custom="" if [ "$MULTISITE" != "yes" ] ; then
if ls /modsec-crs-confs/*.conf > /dev/null 2>&1 ; then modsec_crs_custom=""
modsec_crs_custom="include /modsec-crs-confs/*.conf\n" if ls /modsec-crs-confs/*.conf > /dev/null 2>&1 ; then
modsec_crs_custom="include /modsec-crs-confs/*.conf\n"
fi
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" "$modsec_crs_custom"
fi fi
if [ "$MULTISITE" = "yes" ] && ls /modsec-crs-confs/${1}/*.conf > /dev/null 2>&1 ; then
modsec_crs_custom="${modsec_custom}include /modsec-crs-confs/${1}/*.conf\n"
fi
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" "$modsec_crs_custom"
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS_RULES%" "include /etc/nginx/owasp-crs/*.conf" replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS_RULES%" "include /etc/nginx/owasp-crs/*.conf"
else else
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" "" replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" ""

View File

@ -9,9 +9,9 @@ services:
- 80:8080 - 80:8080
- 443:8443 - 443:8443
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/etc/letsencrypt - ./letsencrypt:/etc/letsencrypt
- ./web-files:/www:ro - ./web-files:/www:ro
- autoconf:/etc/nginx
environment: environment:
- SERVER_NAME= # must be left blank if you don't want to setup "static" conf - SERVER_NAME= # must be left blank if you don't want to setup "static" conf
- MULTISITE=yes - MULTISITE=yes
@ -21,6 +21,15 @@ services:
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes - USE_BROTLI=yes
labels:
- "bunkerized-nginx.AUTOCONF"
myautoconf:
image: bunkerity/bunkerized-nginx:autoconf
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- autoconf:/etc/nginx
myapp1: myapp1:
image: php:fpm image: php:fpm
@ -51,3 +60,6 @@ services:
- "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain - "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain
- "bunkerized-nginx.REMOTE_PHP=myapp3" - "bunkerized-nginx.REMOTE_PHP=myapp3"
- "bunkerized-nginx.REMOTE_PHP_PATH=/app" - "bunkerized-nginx.REMOTE_PHP_PATH=/app"
volumes:
autoconf:

View File

@ -9,8 +9,8 @@ services:
- 80:8080 - 80:8080
- 443:8443 - 443:8443
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/etc/letsencrypt - ./letsencrypt:/etc/letsencrypt
- autoconf:/etc/nginx
environment: environment:
- SERVER_NAME= # must be left blank if you don't want to setup "static" conf - SERVER_NAME= # must be left blank if you don't want to setup "static" conf
- MULTISITE=yes - MULTISITE=yes
@ -22,6 +22,13 @@ services:
- USE_BROTLI=yes - USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
myautoconf:
image: bunkerity/bunkerized-nginx:autoconf
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- autoconf:/etc/nginx
myapp1: myapp1:
build: js-app build: js-app
restart: always restart: always
@ -51,3 +58,6 @@ services:
- "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain - "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain
- "bunkerized-nginx.REVERSE_PROXY_URL=/" - "bunkerized-nginx.REVERSE_PROXY_URL=/"
- "bunkerized-nginx.REVERSE_PROXY_HOST=http://myapp3:3000" - "bunkerized-nginx.REVERSE_PROXY_HOST=http://myapp3:3000"
volumes:
autoconf: