diff --git a/confs2/global/abusers.list b/confs2/global/abusers.list new file mode 100644 index 0000000..e69de29 diff --git a/confs2/global/api-temp.conf b/confs2/global/api-temp.conf new file mode 100644 index 0000000..5a5146b --- /dev/null +++ b/confs2/global/api-temp.conf @@ -0,0 +1,32 @@ + +location ~ ^%API_URI%/ping { + return 444; +} + +location ~ ^%API_URI% { + +rewrite_by_lua_block { + + local api = require "api" + local api_whitelist_ip = {{ API_WHITELIST_IP }} + local api_uri = "%API_URI%" + local logger = require "logger" + + if api.is_api_call(api_uri, api_whitelist_ip) then + ngx.header.content_type = 'text/plain' + if api.do_api_call(api_uri) then + logger.log(ngx.NOTICE, "API", "API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr) + ngx.say("ok") + else + logger.log(ngx.WARN, "API", "API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr) + ngx.say("ko") + end + + ngx.exit(ngx.HTTP_OK) + + end + + ngx.exit(ngx.OK) +} + +} diff --git a/confs2/global/api.conf b/confs2/global/api.conf new file mode 100644 index 0000000..e74a272 --- /dev/null +++ b/confs2/global/api.conf @@ -0,0 +1,31 @@ +{{ API_URI }} +{% set API_WHITELIST_IP_value = "" %} +{% for element in API_WHITELIST_IP.split(" ") %} + {{ element + "toto" }} + {% set API_WHITELIST_IP_value = API_WHITELIST_IP_value + '"' + element + '",' %} +{% endfor %} +{% set API_WHITELIST_IP_value = API_WHITELIST_IP_value[:-1] %} + +rewrite_by_lua_block { + + local api = require "api" + local api_whitelist_ip = {% raw %}{{% endraw %}{% set elements = API_WHITELIST_IP.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% raw %}}{% endraw %} + local api_uri = "%API_URI%" + local logger = require "logger" + + if api.is_api_call(api_uri, api_whitelist_ip) then + ngx.header.content_type = 'text/plain' + if api.do_api_call(api_uri) then + logger.log(ngx.NOTICE, "API", "API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr) + ngx.say("ok") + else + logger.log(ngx.WARN, "API", "API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr) + ngx.say("ko") + end + + ngx.exit(ngx.HTTP_OK) + + end + + ngx.exit(ngx.OK) +} diff --git a/confs2/global/cache.conf b/confs2/global/cache.conf new file mode 100644 index 0000000..2b12cfd --- /dev/null +++ b/confs2/global/cache.conf @@ -0,0 +1,4 @@ +open_file_cache %CACHE%; +open_file_cache_errors %CACHE_ERRORS%; +open_file_cache_min_uses %CACHE_USES%; +open_file_cache_valid %CACHE_VALID%; diff --git a/confs2/global/dhparam b/confs2/global/dhparam new file mode 100644 index 0000000..088f967 --- /dev/null +++ b/confs2/global/dhparam @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- \ No newline at end of file diff --git a/confs2/global/geoip.conf b/confs2/global/geoip.conf new file mode 100644 index 0000000..77399f0 --- /dev/null +++ b/confs2/global/geoip.conf @@ -0,0 +1,10 @@ +geoip2 /etc/nginx/geoip.mmdb { + auto_reload 5m; + $geoip2_metadata_country_build metadata build_epoch; + $geoip2_data_country_code country iso_code; +} + +map $geoip2_data_country_code $allowed_country { + default %DEFAULT%; + %COUNTRY% +} diff --git a/confs2/global/init-lua.conf b/confs2/global/init-lua.conf new file mode 100644 index 0000000..f947cc6 --- /dev/null +++ b/confs2/global/init-lua.conf @@ -0,0 +1,43 @@ +init_by_lua_block { + +local dataloader = require "dataloader" +local logger = require "logger" + +local use_proxies = %USE_PROXIES% +local use_abusers = %USE_ABUSERS% +local use_tor_exit_nodes = %USE_TOR_EXIT_NODES% +local use_user_agents = %USE_USER_AGENTS% +local use_referrers = %USE_REFERRERS% +local use_crowdsec = %USE_CROWDSEC% + +if use_proxies then + dataloader.load_ip("/etc/nginx/proxies.list", ngx.shared.proxies_data) +end + +if use_abusers then + dataloader.load_ip("/etc/nginx/abusers.list", ngx.shared.abusers_data) +end + +if use_tor_exit_nodes then + dataloader.load_ip("/etc/nginx/tor-exit-nodes.list", ngx.shared.tor_exit_nodes_data) +end + +if use_user_agents then + dataloader.load_raw("/etc/nginx/user-agents.list", ngx.shared.user_agents_data) +end + +if use_referrers then + dataloader.load_raw("/etc/nginx/referrers.list", ngx.shared.referrers_data) +end + +if use_crowdsec then + local cs = require "crowdsec.CrowdSec" + local ok, err = cs.init("/etc/nginx/crowdsec.conf") + if ok == nil then + logger.log(ngx.ERR, "CROWDSEC", err) + error() + end + logger.log(ngx.ERR, "CROWDSEC", "*NOT AN ERROR* initialisation done") +end + +} diff --git a/confs2/global/multisite-default-server-https.conf b/confs2/global/multisite-default-server-https.conf new file mode 100644 index 0000000..7f78bb9 --- /dev/null +++ b/confs2/global/multisite-default-server-https.conf @@ -0,0 +1,11 @@ +listen 0.0.0.0:%HTTPS_PORT% default_server ssl %HTTP2%; +ssl_certificate /etc/nginx/default-cert.pem; +ssl_certificate_key /etc/nginx/default-key.pem; +ssl_protocols %HTTPS_PROTOCOLS%; +ssl_prefer_server_ciphers off; +ssl_session_tickets off; +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; +%SSL_DHPARAM% +%SSL_CIPHERS% +%LETS_ENCRYPT_WEBROOT% diff --git a/confs2/global/multisite-default-server-lets-encrypt-webroot.conf b/confs2/global/multisite-default-server-lets-encrypt-webroot.conf new file mode 100644 index 0000000..5b8e707 --- /dev/null +++ b/confs2/global/multisite-default-server-lets-encrypt-webroot.conf @@ -0,0 +1,3 @@ +location ~ ^/.well-known/acme-challenge/ { + root /acme-challenge; +} diff --git a/confs2/global/multisite-default-server.conf b/confs2/global/multisite-default-server.conf new file mode 100644 index 0000000..fc48b42 --- /dev/null +++ b/confs2/global/multisite-default-server.conf @@ -0,0 +1,6 @@ +server { + %LISTEN_HTTP% + server_name _; + %USE_HTTPS% + %MULTISITE_DISABLE_DEFAULT_SERVER% +} diff --git a/confs2/global/multisite-disable-default-server.conf b/confs2/global/multisite-disable-default-server.conf new file mode 100644 index 0000000..9c2ea8a --- /dev/null +++ b/confs2/global/multisite-disable-default-server.conf @@ -0,0 +1,3 @@ +location / { + return 444; +} diff --git a/confs2/global/nginx-temp.conf b/confs2/global/nginx-temp.conf new file mode 100644 index 0000000..50c50cd --- /dev/null +++ b/confs2/global/nginx-temp.conf @@ -0,0 +1,30 @@ +load_module /usr/lib/nginx/modules/ngx_http_lua_module.so; + +daemon on; + +pid /tmp/nginx-temp.pid; + +events { + worker_connections 1024; + use epoll; +} + +http { + proxy_temp_path /tmp/proxy_temp; + client_body_temp_path /tmp/client_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + lua_package_path "/usr/local/lib/lua/?.lua;;"; + server { + listen 0.0.0.0:%HTTP_PORT% default_server; + server_name _; + location ~ ^/.well-known/acme-challenge/ { + root /acme-challenge; + } + %USE_API% + location / { + return 444; + } + } +} diff --git a/confs2/global/nginx.conf b/confs2/global/nginx.conf new file mode 100644 index 0000000..d8e59a0 --- /dev/null +++ b/confs2/global/nginx.conf @@ -0,0 +1,120 @@ +# /etc/nginx/nginx.conf + +# load dynamic modules +load_module /usr/lib/nginx/modules/ngx_http_cookie_flag_filter_module.so; +load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so; +load_module /usr/lib/nginx/modules/ngx_http_headers_more_filter_module.so; +load_module /usr/lib/nginx/modules/ngx_http_lua_module.so; +load_module /usr/lib/nginx/modules/ngx_http_modsecurity_module.so; +load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so; +load_module /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so; +load_module /usr/lib/nginx/modules/ngx_http_brotli_static_module.so; + +# run in foreground +daemon off; + +# PID file +pid /tmp/nginx.pid; + +# worker number = CPU core(s) +worker_processes auto; + +# faster regexp +pcre_jit on; + +# config files for dynamic modules +include /etc/nginx/modules/*.conf; + +# max open files for each worker +worker_rlimit_nofile %WORKER_RLIMIT_NOFILE%; + +events { + # max connections per worker + worker_connections %WORKER_CONNECTIONS%; + + # epoll seems to be the best on Linux + use epoll; +} + +http { + # zero copy within the kernel + sendfile on; + + # send packets only if filled + tcp_nopush on; + + # remove 200ms delay + tcp_nodelay on; + + # load mime types and set default one + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # write logs to local syslog + log_format logf '%LOG_FORMAT%'; + access_log /var/log/access.log logf; + error_log /var/log/error.log %LOG_LEVEL%; + + # temp paths + proxy_temp_path /tmp/proxy_temp; + client_body_temp_path /tmp/client_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + + # close connections in FIN_WAIT1 state + reset_timedout_connection on; + + # timeouts + client_body_timeout 10; + client_header_timeout 10; + keepalive_timeout 15; + send_timeout 10; + + # resolvers to use + resolver %DNS_RESOLVERS% ipv6=off; + + # remove ports when sending redirects + port_in_redirect off; + + # lua path and dicts + lua_package_path "/usr/local/lib/lua/?.lua;;"; + %WHITELIST_IP_CACHE% + %WHITELIST_REVERSE_CACHE% + %BLACKLIST_IP_CACHE% + %BLACKLIST_REVERSE_CACHE% + %DNSBL_CACHE% + %BLOCK_PROXIES% + %BLOCK_ABUSERS% + %BLOCK_TOR_EXIT_NODES% + %BLOCK_USER_AGENTS% + %BLOCK_REFERRERS% + %BAD_BEHAVIOR% + + # shared memory zone for limit_req + %LIMIT_REQ_ZONE% + + # shared memory zone for limit_conn + %LIMIT_CONN_ZONE% + + # whitelist or blacklist country + %USE_COUNTRY% + + # zone for proxy_cache + %PROXY_CACHE_PATH% + + # custom http confs + include /http-confs/*.conf; + + # LUA init block + include /etc/nginx/init-lua.conf; + + # default server when MULTISITE=yes + %MULTISITE_DEFAULT_SERVER% + + # server config(s) + %INCLUDE_SERVER% + + # API + %USE_API% +} diff --git a/confs2/global/proxies.list b/confs2/global/proxies.list new file mode 100644 index 0000000..e69de29 diff --git a/confs2/global/referrers.list b/confs2/global/referrers.list new file mode 100644 index 0000000..e69de29 diff --git a/confs2/global/tor-exit-nodes.list b/confs2/global/tor-exit-nodes.list new file mode 100644 index 0000000..e69de29 diff --git a/confs2/global/user-agents.list b/confs2/global/user-agents.list new file mode 100644 index 0000000..e69de29 diff --git a/confs2/site/antibot-captcha.conf b/confs2/site/antibot-captcha.conf new file mode 100644 index 0000000..85d24bf --- /dev/null +++ b/confs2/site/antibot-captcha.conf @@ -0,0 +1,46 @@ +location = %ANTIBOT_URI% { + + default_type 'text/html'; + + if ($request_method = GET) { + content_by_lua_block { + local cookie = require "cookie" + local captcha = require "captcha" + local logger = require "logger" + if not cookie.is_set("uri") then + logger.log(ngx.WARN, "ANTIBOT", "captcha fail (1) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local img, res = captcha.get_challenge() + cookie.set({captchares = res}) + local code = captcha.get_code(img, "%ANTIBOT_URI%") + ngx.say(code) + } + } + + if ($request_method = POST) { + access_by_lua_block { + local cookie = require "cookie" + local captcha = require "captcha" + local logger = require "logger" + if not cookie.is_set("captchares") then + logger.log(ngx.WARN, "ANTIBOT", "captcha fail (2) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + ngx.req.read_body() + local args, err = ngx.req.get_post_args(1) + if err == "truncated" or not args or not args["captcha"] then + logger.log(ngx.WARN, "ANTIBOT", "captcha fail (3) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local captcha_user = args["captcha"] + local check = captcha.check(captcha_user, cookie.get("captchares")) + if not check then + logger.log(ngx.WARN, "ANTIBOT", "captcha fail (4) for " .. ngx.var.remote_addr) + return ngx.redirect("%ANTIBOT_URI%") + end + cookie.set({captcha = "ok"}) + return ngx.redirect(cookie.get("uri")) + } + } +} diff --git a/confs2/site/antibot-javascript.conf b/confs2/site/antibot-javascript.conf new file mode 100644 index 0000000..2052b9d --- /dev/null +++ b/confs2/site/antibot-javascript.conf @@ -0,0 +1,45 @@ +location = %ANTIBOT_URI% { + + default_type 'text/html'; + + if ($request_method = GET) { + content_by_lua_block { + local cookie = require "cookie" + local javascript = require "javascript" + local logger = require "logger" + if not cookie.is_set("challenge") then + logger.log(ngx.WARN, "ANTIBOT", "javascript fail (1) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local challenge = cookie.get("challenge") + local code = javascript.get_code(challenge, "%ANTIBOT_URI%", cookie.get("uri")) + ngx.say(code) + } + } + + if ($request_method = POST) { + content_by_lua_block { + local cookie = require "cookie" + local javascript = require "javascript" + local logger = require "logger" + if not cookie.is_set("challenge") then + logger.log(ngx.WARN, "ANTIBOT", "javascript fail (2) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + ngx.req.read_body() + local args, err = ngx.req.get_post_args(1) + if err == "truncated" or not args or not args["challenge"] then + logger.log(ngx.WARN, "ANTIBOT", "javascript fail (3) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local challenge = args["challenge"] + local check = javascript.check(cookie.get("challenge"), challenge) + if not check then + logger.log(ngx.WARN, "ANTIBOT", "javascript fail (4) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + cookie.set({javascript = "ok"}) + return ngx.exit(ngx.OK) + } + } +} diff --git a/confs2/site/antibot-recaptcha.conf b/confs2/site/antibot-recaptcha.conf new file mode 100644 index 0000000..d901f36 --- /dev/null +++ b/confs2/site/antibot-recaptcha.conf @@ -0,0 +1,44 @@ +location = %ANTIBOT_URI% { + + default_type 'text/html'; + + if ($request_method = GET) { + content_by_lua_block { + local cookie = require "cookie" + local recaptcha = require "recaptcha" + local loggger = require "logger" + if not cookie.is_set("uri") then + logger.log(ngx.WARN, "ANTIBOT", "recaptcha fail (1) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local code = recaptcha.get_code("%ANTIBOT_URI%", "%ANTIBOT_RECAPTCHA_SITEKEY%") + ngx.say(code) + } + } + + if ($request_method = POST) { + access_by_lua_block { + local cookie = require "cookie" + local recaptcha = require "recaptcha" + local logger = require "logger" + if not cookie.is_set("uri") then + logger.log(ngx.WARN, "ANTIBOT", "recaptcha fail (2) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + ngx.req.read_body() + local args, err = ngx.req.get_post_args(1) + if err == "truncated" or not args or not args["token"] then + logger.log(ngx.WARN, "ANTIBOT", "recaptcha fail (3) for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + local token = args["token"] + local check = recaptcha.check(token, "%ANTIBOT_RECAPTCHA_SECRET%") + if check < %ANTIBOT_RECAPTCHA_SCORE% then + logger.log(ngx.WARN, "ANTIBOT", "recaptcha fail (4) for " .. ngx.var.remote_addr .. " (score = " .. tostring(check) .. ")") + return ngx.exit(ngx.HTTP_FORBIDDEN) + end + cookie.set({recaptcha = "ok"}) + return ngx.redirect(cookie.get("uri")) + } + } +} diff --git a/confs2/site/auth-basic-sitewide.conf b/confs2/site/auth-basic-sitewide.conf new file mode 100644 index 0000000..6fce64b --- /dev/null +++ b/confs2/site/auth-basic-sitewide.conf @@ -0,0 +1,2 @@ +auth_basic "%AUTH_BASIC_TEXT%"; +auth_basic_user_file %NGINX_PREFIX%.htpasswd; diff --git a/confs2/site/auth-basic.conf b/confs2/site/auth-basic.conf new file mode 100644 index 0000000..f2668ed --- /dev/null +++ b/confs2/site/auth-basic.conf @@ -0,0 +1,4 @@ +location %AUTH_BASIC_LOCATION% { + auth_basic "%AUTH_BASIC_TEXT%"; + auth_basic_user_file %NGINX_PREFIX%.htpasswd; +} diff --git a/confs2/site/brotli.conf b/confs2/site/brotli.conf new file mode 100644 index 0000000..734513a --- /dev/null +++ b/confs2/site/brotli.conf @@ -0,0 +1,4 @@ +brotli on; +brotli_types %BROTLI_TYPES%; +brotli_comp_level %BROTLI_COMP_LEVEL%; +brotli_min_length %BROTLI_MIN_LENGTH%; diff --git a/confs2/site/client-cache.conf b/confs2/site/client-cache.conf new file mode 100644 index 0000000..21271f7 --- /dev/null +++ b/confs2/site/client-cache.conf @@ -0,0 +1,6 @@ +etag %CLIENT_CACHE_ETAG%; +set $cache ""; +if ($uri ~* \.(%CLIENT_CACHE_EXTENSIONS%)$) { + set $cache "%CLIENT_CACHE_CONTROL%"; +} +add_header Cache-Control $cache; diff --git a/confs2/site/content-security-policy.conf b/confs2/site/content-security-policy.conf new file mode 100644 index 0000000..11e3338 --- /dev/null +++ b/confs2/site/content-security-policy.conf @@ -0,0 +1 @@ +more_set_headers "Content-Security-Policy: %CONTENT_SECURITY_POLICY%"; diff --git a/confs2/site/cookie-flags.conf b/confs2/site/cookie-flags.conf new file mode 100644 index 0000000..e81ec79 --- /dev/null +++ b/confs2/site/cookie-flags.conf @@ -0,0 +1 @@ +set_cookie_flag %COOKIE_FLAGS%; diff --git a/confs2/site/custom-https.conf b/confs2/site/custom-https.conf new file mode 100644 index 0000000..88289a8 --- /dev/null +++ b/confs2/site/custom-https.conf @@ -0,0 +1,7 @@ +listen 0.0.0.0:443 ssl %HTTP2%; +ssl_certificate %HTTPS_CUSTOM_CERT%; +ssl_certificate_key %HTTPS_CUSTOM_KEY%; +ssl_protocols TLSv1.3; +ssl_prefer_server_ciphers off; +ssl_session_tickets off; +%STRICT_TRANSPORT_SECURITY% diff --git a/confs2/site/disable-default-server.conf b/confs2/site/disable-default-server.conf new file mode 100644 index 0000000..104794d --- /dev/null +++ b/confs2/site/disable-default-server.conf @@ -0,0 +1,3 @@ +if ($host !~ ^(%SERVER_NAME%)$) { + return 444; +} diff --git a/confs2/site/error.conf b/confs2/site/error.conf new file mode 100644 index 0000000..af44ffe --- /dev/null +++ b/confs2/site/error.conf @@ -0,0 +1,7 @@ +error_page %CODE% %PAGE%; + +location = %PAGE% { + root %ROOT_FOLDER%; + modsecurity off; + internal; +} diff --git a/confs2/site/fastcgi.conf b/confs2/site/fastcgi.conf new file mode 100644 index 0000000..acd0b38 --- /dev/null +++ b/confs2/site/fastcgi.conf @@ -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; diff --git a/confs2/site/feature-policy.conf b/confs2/site/feature-policy.conf new file mode 100644 index 0000000..64c6e8e --- /dev/null +++ b/confs2/site/feature-policy.conf @@ -0,0 +1 @@ +more_set_headers "Feature-Policy: %FEATURE_POLICY%"; diff --git a/confs2/site/gzip.conf b/confs2/site/gzip.conf new file mode 100644 index 0000000..f0f77fc --- /dev/null +++ b/confs2/site/gzip.conf @@ -0,0 +1,4 @@ +gzip on; +gzip_comp_level %GZIP_COMP_LEVEL%; +gzip_min_length %GZIP_MIN_LENGTH%; +gzip_types %GZIP_TYPES%; diff --git a/confs2/site/https.conf b/confs2/site/https.conf new file mode 100644 index 0000000..5a50735 --- /dev/null +++ b/confs2/site/https.conf @@ -0,0 +1,12 @@ +listen 0.0.0.0:%HTTPS_PORT% ssl %HTTP2%; +ssl_certificate %HTTPS_CERT%; +ssl_certificate_key %HTTPS_KEY%; +ssl_protocols %HTTPS_PROTOCOLS%; +ssl_prefer_server_ciphers on; +ssl_session_tickets off; +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; +%STRICT_TRANSPORT_SECURITY% +%SSL_DHPARAM% +%SSL_CIPHERS% +%LETS_ENCRYPT_WEBROOT% diff --git a/confs2/site/lets-encrypt-webroot.conf b/confs2/site/lets-encrypt-webroot.conf new file mode 100644 index 0000000..5b8e707 --- /dev/null +++ b/confs2/site/lets-encrypt-webroot.conf @@ -0,0 +1,3 @@ +location ~ ^/.well-known/acme-challenge/ { + root /acme-challenge; +} diff --git a/confs2/site/limit-conn.conf b/confs2/site/limit-conn.conf new file mode 100644 index 0000000..6482ad5 --- /dev/null +++ b/confs2/site/limit-conn.conf @@ -0,0 +1 @@ +limit_conn ddos %LIMIT_CONN_MAX%; diff --git a/confs2/site/limit-req.conf b/confs2/site/limit-req.conf new file mode 100644 index 0000000..395d838 --- /dev/null +++ b/confs2/site/limit-req.conf @@ -0,0 +1,3 @@ +limit_req_status 429; +limit_req zone=limit burst=%LIMIT_REQ_BURST% nodelay; + diff --git a/confs2/site/log-lua.conf b/confs2/site/log-lua.conf new file mode 100644 index 0000000..13854f3 --- /dev/null +++ b/confs2/site/log-lua.conf @@ -0,0 +1,15 @@ +log_by_lua_block { + +-- bad behavior +local use_bad_behavior = %USE_BAD_BEHAVIOR% +local behavior = require "behavior" +local bad_behavior_status_codes = {{ BAD_BEHAVIOR_STATUS_CODES }} +local bad_behavior_threshold = %BAD_BEHAVIOR_THRESHOLD% +local bad_behavior_count_time = %BAD_BEHAVIOR_COUNT_TIME% +local bad_behavior_ban_time = %BAD_BEHAVIOR_BAN_TIME% + +if use_bad_behavior then + behavior.count(bad_behavior_status_codes, bad_behavior_threshold, bad_behavior_count_time, bad_behavior_ban_time) +end + +} diff --git a/confs2/site/main-lua.conf b/confs2/site/main-lua.conf new file mode 100644 index 0000000..3ea0b57 --- /dev/null +++ b/confs2/site/main-lua.conf @@ -0,0 +1,298 @@ +set $session_secret %ANTIBOT_SESSION_SECRET%; +set $session_check_addr on; + +access_by_lua_block { + +-- let's encrypt +local use_lets_encrypt = %USE_LETS_ENCRYPT% + +-- external blacklists +local use_user_agents = %USE_USER_AGENTS% +local use_proxies = %USE_PROXIES% +local use_abusers = %USE_ABUSERS% +local use_tor_exit_nodes = %USE_TOR_EXIT_NODES% +local use_referrers = %USE_REFERRERS% + +-- countries +local use_country = %USE_COUNTRY% + +-- crowdsec +local use_crowdsec = %USE_CROWDSEC% + +-- antibot +local use_antibot_cookie = %USE_ANTIBOT_COOKIE% +local use_antibot_javascript = %USE_ANTIBOT_JAVASCRIPT% +local use_antibot_captcha = %USE_ANTIBOT_CAPTCHA% +local use_antibot_recaptcha = %USE_ANTIBOT_RECAPTCHA% + +-- resolvers +local dns_resolvers = {{ DNS_RESOLVERS }} + +-- whitelist +local use_whitelist_ip = %USE_WHITELIST_IP% +local use_whitelist_reverse = %USE_WHITELIST_REVERSE% +local whitelist_ip_list = {{ WHITELIST_IP_LIST }} +local whitelist_reverse_list = {{ WHITELIST_REVERSE_LIST }} + +-- blacklist +local use_blacklist_ip = %USE_BLACKLIST_IP% +local use_blacklist_reverse = %USE_BLACKLIST_REVERSE% +local blacklist_ip_list = {{ BLACKLIST_IP_LIST }} +local blacklist_reverse_list = {{ BLACKLIST_REVERSE_LIST }} + +-- dnsbl +local use_dnsbl = %USE_DNSBL% +local dnsbl_list = {{ DNSBL_LIST }} + +-- bad behavior +local use_bad_behavior = %USE_BAD_BEHAVIOR% + +-- include LUA code +local whitelist = require "whitelist" +local blacklist = require "blacklist" +local dnsbl = require "dnsbl" +local cookie = require "cookie" +local javascript = require "javascript" +local captcha = require "captcha" +local recaptcha = require "recaptcha" +local iputils = require "resty.iputils" +local behavior = require "behavior" +local logger = require "logger" + +-- user variables +local antibot_uri = "%ANTIBOT_URI%" +local whitelist_user_agent = {{ WHITELIST_USER_AGENT }} +local whitelist_uri = {{ WHITELIST_URI }} + +-- check if already in whitelist cache +if use_whitelist_ip and whitelist.ip_cached_ok() then + ngx.exit(ngx.OK) +end +if use_whitelist_reverse and whitelist.reverse_cached_ok() then + ngx.exit(ngx.OK) +end + +-- check if already in blacklist cache +if use_blacklist_ip and blacklist.ip_cached_ko() then + ngx.exit(ngx.HTTP_FORBIDDEN) +end +if use_blacklist_reverse and blacklist.reverse_cached_ko() then + ngx.exit(ngx.HTTP_FORBIDDEN) +end + +-- check if already in dnsbl cache +if use_dnsbl and dnsbl.cached_ko() then + ngx.exit(ngx.HTTP_FORBIDDEN) +end + +-- check if IP is whitelisted (only if not in cache) +if use_whitelist_ip and not whitelist.ip_cached() then + if whitelist.check_ip(whitelist_ip_list) then + ngx.exit(ngx.OK) + end +end + +-- check if reverse is whitelisted (only if not in cache) +if use_whitelist_reverse and not whitelist.reverse_cached() then + if whitelist.check_reverse(whitelist_reverse_list) then + ngx.exit(ngx.OK) + end +end + +-- check if URI is whitelisted +for k, v in pairs(whitelist_uri) do + if ngx.var.request_uri == v then + logger.log(ngx.NOTICE, "WHITELIST", "URI " .. v .. " is whitelisted") + ngx.exit(ngx.OK) + end +end + +-- check if it's certbot +if use_lets_encrypt and string.match(ngx.var.request_uri, "^/.well-known/acme-challenge/") then + logger.log(ngx.INFO, "LETSENCRYPT", "got a visit from Let's Encrypt") + ngx.exit(ngx.OK) +end + +-- check if IP is blacklisted (only if not in cache) +if use_blacklist_ip and not blacklist.ip_cached() then + if blacklist.check_ip(blacklist_ip_list) then + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if reverse is blacklisted (only if not in cache) +if use_blacklist_reverse and not blacklist.reverse_cached() then + if blacklist.check_reverse(blacklist_reverse_list, dns_resolvers) then + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if IP is banned because of "bad behavior" +if use_bad_behavior and behavior.is_banned() then + logger.log(ngx.WARN, "BEHAVIOR", "IP " .. ngx.var.remote_addr .. " is banned because of bad behavior") + ngx.exit(ngx.HTTP_FORBIDDEN) +end + +-- check if IP is in proxies list +if use_proxies then + local value, flags = ngx.shared.proxies_data:get(iputils.ip2bin(ngx.var.remote_addr)) + if value ~= nil then + logger.log(ngx.WARN, "PROXIES", "IP " .. ngx.var.remote_addr .. " is in proxies list") + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if IP is in abusers list +if use_abusers then + local value, flags = ngx.shared.abusers_data:get(iputils.ip2bin(ngx.var.remote_addr)) + if value ~= nil then + logger.log(ngx.WARN, "ABUSERS", "IP " .. ngx.var.remote_addr .. " is in abusers list") + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if IP is in TOR exit nodes list +if use_tor_exit_nodes then + local value, flags = ngx.shared.tor_exit_nodes_data:get(iputils.ip2bin(ngx.var.remote_addr)) + if value ~= nil then + logger.log(ngx.WARN, "TOR", "IP " .. ngx.var.remote_addr .. " is in TOR exit nodes list") + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if user-agent is allowed +if use_user_agents and ngx.var.http_user_agent ~= nil then + local whitelisted = false + for k, v in pairs(whitelist_user_agent) do + if string.match(ngx.var.http_user_agent, v) then + logger.log(ngx.NOTICE, "WHITELIST", "User-Agent " .. ngx.var.http_user_agent .. " is whitelisted") + whitelisted = true + break + end + end + if not whitelisted then + local value, flags = ngx.shared.user_agents_cache:get(ngx.var.http_user_agent) + if value == nil then + local patterns = ngx.shared.user_agents_data:get_keys(0) + for i, pattern in ipairs(patterns) do + if string.match(ngx.var.http_user_agent, pattern) then + value = "ko" + ngx.shared.user_agents_cache:set(ngx.var.http_user_agent, "ko", 86400) + break + end + end + if value == nil then + value = "ok" + ngx.shared.user_agents_cache:set(ngx.var.http_user_agent, "ok", 86400) + end + end + if value == "ko" then + logger.log(ngx.WARN, "USER-AGENT", "User-Agent " .. ngx.var.http_user_agent .. " is blacklisted") + ngx.exit(ngx.HTTP_FORBIDDEN) + end + end +end + +-- check if referrer is allowed +if use_referrer and ngx.var.http_referer ~= nil then + local value, flags = ngx.shared.referrers_cache:get(ngx.var.http_referer) + if value == nil then + local patterns = ngx.shared.referrers_data:get_keys(0) + for i, pattern in ipairs(patterns) do + if string.match(ngx.var.http_referer, pattern) then + value = "ko" + ngx.shared.referrers_cache:set(ngx.var.http_referer, "ko", 86400) + break + end + end + if value == nil then + value = "ok" + ngx.shared.referrers_cache:set(ngx.var.http_referer, "ok", 86400) + end + end + if value == "ko" then + logger.log(ngx.WARN, "REFERRER", "Referrer " .. ngx.var.http_referer .. " is blacklisted") + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if country is allowed +if use_country and ngx.var.allowed_country == "no" then + logger.log(ngx.WARN, "COUNTRY", "Country of " .. ngx.var.remote_addr .. " is blacklisted") + ngx.exit(ngx.HTTP_FORBIDDEN) +end + +-- check if IP is in DNSBLs (only if not in cache) +if use_dnsbl and not dnsbl.cached() then + if dnsbl.check(dnsbl_list, dns_resolvers) then + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- check if IP is in CrowdSec DB +if use_crowdsec then + local ok, err = require "crowdsec.CrowdSec".allowIp(ngx.var.remote_addr) + if ok == nil then + logger.log(ngx.ERR, "CROWDSEC", err) + end + if not ok then + logger.log(ngx.WARN, "CROWDSEC", "denied " .. ngx.var.remote_addr) + ngx.exit(ngx.HTTP_FORBIDDEN) + end +end + +-- cookie check +if use_antibot_cookie and ngx.var.uri ~= "/favicon.ico" then + if not cookie.is_set("uri") then + if ngx.var.request_uri ~= antibot_uri then + cookie.set({uri = ngx.var.request_uri}) + return ngx.redirect(antibot_uri) + end + logger.log(ngx.WARN, "ANTIBOT", "cookie fail for " .. ngx.var.remote_addr) + return ngx.exit(ngx.HTTP_FORBIDDEN) + else + if ngx.var.request_uri == antibot_uri then + return ngx.redirect(cookie.get("uri")) + end + end +end + +-- javascript check +if use_antibot_javascript and ngx.var.uri ~= "/favicon.ico" then + if not cookie.is_set("javascript") then + if ngx.var.request_uri ~= antibot_uri then + cookie.set({uri = ngx.var.request_uri, challenge = javascript.get_challenge()}) + return ngx.redirect(antibot_uri) + end + end +end + +-- captcha check +if use_antibot_captcha and ngx.var.uri ~= "/favicon.ico" then + if not cookie.is_set("captcha") then + if ngx.var.request_uri ~= antibot_uri then + cookie.set({uri = ngx.var.request_uri}) + return ngx.redirect(antibot_uri) + end + end +end + +-- recaptcha check +if use_antibot_recaptcha and ngx.var.uri ~= "/favicon.ico" then + if not cookie.is_set("recaptcha") then + if ngx.var.request_uri ~= antibot_uri then + cookie.set({uri = ngx.var.request_uri}) + return ngx.redirect(antibot_uri) + end + end +end + +ngx.exit(ngx.OK) + +} + +%INCLUDE_ANTIBOT_JAVASCRIPT% + +%INCLUDE_ANTIBOT_CAPTCHA% + +%INCLUDE_ANTIBOT_RECAPTCHA% diff --git a/confs2/site/modsecurity-clamav.conf b/confs2/site/modsecurity-clamav.conf new file mode 100644 index 0000000..af96b0f --- /dev/null +++ b/confs2/site/modsecurity-clamav.conf @@ -0,0 +1,4 @@ +SecUploadDir /tmp +SecUploadKeepFiles On +SecRule FILES_TMPNAMES "@inspectFile /opt/scripts/clamav.sh" \ +"phase:2,t:none,deny,msg:'Virus found in uploaded file',id:'399999'" diff --git a/confs2/site/modsecurity-rules.conf b/confs2/site/modsecurity-rules.conf new file mode 100644 index 0000000..9efdcf5 --- /dev/null +++ b/confs2/site/modsecurity-rules.conf @@ -0,0 +1,65 @@ +# process rules with disruptive actions +SecRuleEngine On + +# allow body checks +SecRequestBodyAccess On + +# enable XML parsing +SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ + "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" + +# enable JSON parsing +SecRule REQUEST_HEADERS:Content-Type "application/json" \ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + +# maximum data size +SecRequestBodyLimit 13107200 +SecRequestBodyNoFilesLimit 131072 + +# reject requests if bigger than max data size +SecRequestBodyLimitAction Reject + +# reject if we can't process the body +SecRule REQBODY_ERROR "!@eq 0" \ +"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + +# be strict with multipart/form-data body +SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ +"id:'200003',phase:2,t:none,log,deny,status:400, \ +msg:'Multipart request body failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_MISSING_SEMICOLON}, \ +IQ %{MULTIPART_INVALID_QUOTING}, \ +IP %{MULTIPART_INVALID_PART}, \ +IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ +FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" +SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \ + "id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" + +# enable response body checks +SecResponseBodyAccess On +SecResponseBodyMimeType text/plain text/html text/xml application/json +SecResponseBodyLimit 524288 +SecResponseBodyLimitAction ProcessPartial + +# log usefull stuff +SecAuditEngine %MODSECURITY_SEC_AUDIT_ENGINE% +SecAuditLogType Serial +SecAuditLog /var/log/nginx/modsec_audit.log + +# scan uploaded files with clamv +%USE_CLAMAV_UPLOAD% + +# include OWASP CRS rules +%MODSECURITY_INCLUDE_CRS% +%MODSECURITY_INCLUDE_CUSTOM_CRS% +%MODSECURITY_INCLUDE_CRS_RULES% + +# include custom rules +%MODSECURITY_INCLUDE_CUSTOM_RULES% diff --git a/confs2/site/modsecurity.conf b/confs2/site/modsecurity.conf new file mode 100644 index 0000000..b30c0f8 --- /dev/null +++ b/confs2/site/modsecurity.conf @@ -0,0 +1,2 @@ +modsecurity on; +modsecurity_rules_file %MODSEC_RULES_FILE%; diff --git a/confs2/site/open-file-cache.conf b/confs2/site/open-file-cache.conf new file mode 100644 index 0000000..8324dcd --- /dev/null +++ b/confs2/site/open-file-cache.conf @@ -0,0 +1,4 @@ +open_file_cache %OPEN_FILE_CACHE%; +open_file_cache_errors %OPEN_FILE_CACHE_ERRORS%; +open_file_cache_min_uses %OPEN_FILE_CACHE_MIN_USES%; +open_file_cache_valid %OPEN_FILE_CACHE_VALID%; diff --git a/confs2/site/permissions-policy.conf b/confs2/site/permissions-policy.conf new file mode 100644 index 0000000..3877b8d --- /dev/null +++ b/confs2/site/permissions-policy.conf @@ -0,0 +1 @@ +more_set_headers "Permissions-Policy: %PERMISSIONS_POLICY%"; diff --git a/confs2/site/php.conf b/confs2/site/php.conf new file mode 100644 index 0000000..950b986 --- /dev/null +++ b/confs2/site/php.conf @@ -0,0 +1,4 @@ +location ~ \.php$ { + fastcgi_pass %REMOTE_PHP%:9000; + fastcgi_index index.php; +} diff --git a/confs2/site/proxy-cache.conf b/confs2/site/proxy-cache.conf new file mode 100644 index 0000000..37b4a17 --- /dev/null +++ b/confs2/site/proxy-cache.conf @@ -0,0 +1,7 @@ +proxy_cache proxycache; +proxy_cache_methods %PROXY_CACHE_METHODS%; +proxy_cache_min_uses %PROXY_CACHE_MIN_USES%; +proxy_cache_key %PROXY_CACHE_KEY%; +proxy_no_cache %PROXY_NO_CACHE%; +proxy_cache_bypass %PROXY_CACHE_BYPASS%; +%PROXY_CACHE_VALID% diff --git a/confs2/site/proxy-real-ip.conf b/confs2/site/proxy-real-ip.conf new file mode 100644 index 0000000..4d972c4 --- /dev/null +++ b/confs2/site/proxy-real-ip.conf @@ -0,0 +1,4 @@ +%PROXY_REAL_IP_FROM% +real_ip_header %PROXY_REAL_IP_HEADER%; +real_ip_recursive %PROXY_REAL_IP_RECURSIVE%; + diff --git a/confs2/site/redirect-http-to-https.conf b/confs2/site/redirect-http-to-https.conf new file mode 100644 index 0000000..7a9c74d --- /dev/null +++ b/confs2/site/redirect-http-to-https.conf @@ -0,0 +1,3 @@ +if ($scheme = http) { + return 301 https://$host$request_uri; +} diff --git a/confs2/site/referrer-policy.conf b/confs2/site/referrer-policy.conf new file mode 100644 index 0000000..e0dea36 --- /dev/null +++ b/confs2/site/referrer-policy.conf @@ -0,0 +1 @@ +more_set_headers "Referrer-Policy: %REFERRER_POLICY%"; diff --git a/confs2/site/reverse-proxy-headers.conf b/confs2/site/reverse-proxy-headers.conf new file mode 100644 index 0000000..056d7b6 --- /dev/null +++ b/confs2/site/reverse-proxy-headers.conf @@ -0,0 +1,6 @@ +proxy_set_header Host $host; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-Proto $scheme; +proxy_set_header X-Forwarded-Protocol $scheme; +proxy_set_header X-Forwarded-Host $http_host; diff --git a/confs2/site/reverse-proxy.conf b/confs2/site/reverse-proxy.conf new file mode 100644 index 0000000..2db7d08 --- /dev/null +++ b/confs2/site/reverse-proxy.conf @@ -0,0 +1,7 @@ +location %REVERSE_PROXY_URL% { + etag off; + proxy_pass %REVERSE_PROXY_HOST%; + %REVERSE_PROXY_HEADERS% + %REVERSE_PROXY_WS% + %REVERSE_PROXY_CUSTOM_HEADERS% +} diff --git a/confs2/site/serve-files.conf b/confs2/site/serve-files.conf new file mode 100644 index 0000000..d920e93 --- /dev/null +++ b/confs2/site/serve-files.conf @@ -0,0 +1,3 @@ +root %ROOT_FOLDER%; +index index.html index.php; +try_files $uri $uri/ =404; diff --git a/confs2/site/server.conf b/confs2/site/server.conf new file mode 100644 index 0000000..9c619b3 --- /dev/null +++ b/confs2/site/server.conf @@ -0,0 +1,41 @@ +%PRE_SERVER_CONF% + +server { + %FASTCGI_PATH% + %SERVER_CONF% + %PROXY_REAL_IP% + %INCLUDE_LUA% + %USE_MODSECURITY% + %LISTEN_HTTP% + %USE_HTTPS% + %REDIRECT_HTTP_TO_HTTPS% + server_name %SERVER_NAME%; + %DISABLE_DEFAULT_SERVER% + %SERVE_FILES% + if ($request_method !~ ^(%ALLOWED_METHODS%)$) + { + return 405; + } + %LIMIT_REQ% + %LIMIT_CONN% + %AUTH_BASIC% + %REMOVE_HEADERS% + %X_FRAME_OPTIONS% + %X_XSS_PROTECTION% + %X_CONTENT_TYPE_OPTIONS% + %CONTENT_SECURITY_POLICY% + %REFERRER_POLICY% + %FEATURE_POLICY% + %PERMISSIONS_POLICY% + %COOKIE_FLAGS% + %ERRORS% + %USE_CLIENT_CACHE% + %USE_GZIP% + %USE_BROTLI% + client_max_body_size %MAX_CLIENT_SIZE%; + server_tokens %SERVER_TOKENS%; + %USE_OPEN_FILE_CACHE% + %USE_PROXY_CACHE% + %USE_REVERSE_PROXY% + %USE_PHP% +} diff --git a/confs2/site/x-content-type-options.conf b/confs2/site/x-content-type-options.conf new file mode 100644 index 0000000..7bd59ef --- /dev/null +++ b/confs2/site/x-content-type-options.conf @@ -0,0 +1 @@ +more_set_headers "X-Content-Type-Options: %X_CONTENT_TYPE_OPTIONS%"; diff --git a/confs2/site/x-frame-options.conf b/confs2/site/x-frame-options.conf new file mode 100644 index 0000000..52be218 --- /dev/null +++ b/confs2/site/x-frame-options.conf @@ -0,0 +1 @@ +more_set_headers "X-Frame-Options: %X_FRAME_OPTIONS%"; diff --git a/confs2/site/x-xss-protection.conf b/confs2/site/x-xss-protection.conf new file mode 100644 index 0000000..1394cb4 --- /dev/null +++ b/confs2/site/x-xss-protection.conf @@ -0,0 +1 @@ +more_set_headers "X-XSS-Protection: %X_XSS_PROTECTION%"; diff --git a/gen/Settings.py b/gen/Configurator.py similarity index 98% rename from gen/Settings.py rename to gen/Configurator.py index c7f0398..03b8fa4 100644 --- a/gen/Settings.py +++ b/gen/Configurator.py @@ -1,6 +1,6 @@ import json, re -class Settings : +class Configurator : def __init__(self) : self.__settings = {} diff --git a/gen/Templates.py b/gen/Templator.py similarity index 82% rename from gen/Templates.py rename to gen/Templator.py index a101752..3daff02 100644 --- a/gen/Templates.py +++ b/gen/Templator.py @@ -1,6 +1,6 @@ -import jinja2, glob, os, pathlib +import jinja2, glob, os, pathlib, copy -class Templates : +class Templator : def __init__(self, config, input_path) : self.__config = config @@ -14,11 +14,14 @@ class Templates : return self.__render("site", output_path, server_name) def __render(self, type, output_path, server_name=None) : + real_config = copy.deepcopy(self.__config) + if server_name != None : + real_config["SERVER_NAME"] = server_name for filename in glob.iglob(self.__input_path + "/" + type + "**/**", recursive=True) : if os.path.isfile(filename) : relative_filename = filename.replace(self.__input_path, "").replace(type + "/", "") template = self.__template_env.get_template(type + "/" + relative_filename) - output = template.render(self.__config) + output = template.render(real_config) if "/" in relative_filename : directory = relative_filename.replace(relative_filename.split("/")[-1], "") pathlib.Path(output_path + "/" + directory).mkdir(parents=True, exist_ok=True) diff --git a/gen/main.py b/gen/main.py index 4ecf4f8..36117a7 100755 --- a/gen/main.py +++ b/gen/main.py @@ -1,18 +1,67 @@ #!/usr/bin/python3 -from Settings import Settings -from Templates import Templates +import argparse, os, sys + +import utils +from Configurator import Configurator +from Templator import Templator if __name__ == "__main__" : - my_settings = Settings() - my_settings.load_settings("../settings.json") - variables = {} - variables["MULTISITE"] = "yes" - variables["BLOCK_PROXIES"] = "no" - variables["omg"] = "lol" - variables["www.toto.com_BLOCK_PROXIES"] = "yes" - my_settings.load_variables(variables) - print(my_settings.get_config()) - my_templates = Templates(my_settings.get_config(), "/tmp/input") - my_templates.render_global("/tmp/output") + # Parse arguments + parser = argparse.ArgumentParser(description="bunkerized-nginx config generator v1.0") + parser.add_argument("--settings", default="/opt/settings.json", type=str, help="path to the files containing the default settings") + parser.add_argument("--templates", default="/opt/confs", type=str, help="directory containing the templates files") + parser.add_argument("--output", default="/etc/nginx", type=str, help="where to write the rendered files") + parser.add_argument("--variables", default="/opt/variables.env", type=str, help="path to the file containing environment variables") + args = parser.parse_args() + + # Check existences and permissions + if not os.path.exists(args.settings) : + print("[!] Missing settings file : " + args.settings) + sys.exit(1) + if not os.access(args.settings, os.R_OK) : + print("[!] Can't read settings file : " + args.settings) + sys.exit(2) + if not os.path.isdir(args.templates) : + print("[!] Missing templates directory : " + args.templates) + sys.exit(1) + if not os.access(args.templates, os.R_OK | os.X_OK) : + print("[!] Can't read the templates directory : " + args.templates) + sys.exit(2) + if not os.path.isdir(args.output) : + print("[!] Missing output directory : " + args.output) + sys.exit(1) + if not os.access(args.output, os.W_OK | os.X_OK) : + print("[!] Can't write to the templates directory : " + args.output) + sys.exit(2) + if not os.path.exists(args.variables) : + print("[!] Missing variables file : " + args.variables) + sys.exit(1) + if not os.access(args.variables, os.R_OK) : + print("[!] Can't read variables file : " + args.variables) + sys.exit(2) + + # Compute the final config + configurator = Configurator() + configurator.load_settings(args.settings) + variables = utils.load_variables(args.variables) + configurator.load_variables(variables) + config = configurator.get_config() + print(config) + + # Generate the files from templates and config + templator = Templator(config, args.templates) + templator.render_global(args.output) + if config["MULTISITE"] == "no" : + templator.render_site(args.output, config["SERVER_NAME"]) + else : + for server_name in config["SERVER_NAME"].split(" ") : + real_server_name = server_name + if server_name + "_SERVER_NAME" in variables : + real_server_name = variables[server_name + "_SERVER_NAME"] + templator.render_site(args.output, real_server_name) + + # We're done + print("[*] Generation done !") + sys.exit(0) diff --git a/gen/test.txt b/gen/test.txt new file mode 100644 index 0000000..94b0266 --- /dev/null +++ b/gen/test.txt @@ -0,0 +1 @@ +./main.py --settings /opt/work/bunkerized-nginx/settings.json --templates /opt/work/bunkerized-nginx/confs2 --output /tmp/debug --variables /tmp/variables.env diff --git a/gen/utils.py b/gen/utils.py new file mode 100644 index 0000000..745b69c --- /dev/null +++ b/gen/utils.py @@ -0,0 +1,10 @@ +def load_variables(path) : + variables = {} + with open(path) as f : + lines = f.read().splitlines() + for line in lines : + var = line.split("=")[0] + value = line[len(var)+1:] + variables[var] = value + return variables +