├── nginx-dumb-mertics ├── nginx_metrics │ ├── up │ └── .style │ │ └── metrics.xslt └── nginx.conf ├── lua-ffi ├── lua-qrencode.png └── nginx.qrencode.conf ├── nginx-AD-auth ├── etc │ ├── pam.d │ │ └── nginx │ └── pam_ldap.conf └── nginx.conf ├── nginx-yum-repo ├── rebuild-repo.path ├── rebuild-repo.service ├── rebuild_repo.sh └── yum-repo.conf ├── ssl-certs ├── gen_csr.sh ├── check_expire.sh ├── gen_server.sh ├── gen_client.sh ├── nginx-client-cert.conf └── host.tld.csr.conf ├── nginx-google-authenticator ├── etc │ └── pam.d │ │ └── nginx_google ├── createuser.sh └── nginx.conf ├── nginx-stream-ssh ├── ssh_config └── nginx.conf ├── nginx-shell-webhook ├── shell-webhook.service ├── nginx.conf └── shell-webhook ├── error-code-status ├── lua │ ├── status_code_log.lua │ └── status_code_dump.lua └── nginx.conf ├── metrics-aggregation └── status.conf ├── http-session ├── rsyslog.local.conf └── nginx.proxy.conf ├── nginx-extended-limit_rate └── nginx.conf ├── nginx-autoban └── server.conf ├── nginx-modules └── build-modules.sh └── ReadMe.md /nginx-dumb-mertics/nginx_metrics/up: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lua-ffi/lua-qrencode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toxatoor/nginx/HEAD/lua-ffi/lua-qrencode.png -------------------------------------------------------------------------------- /nginx-AD-auth/etc/pam.d/nginx: -------------------------------------------------------------------------------- 1 | auth required /lib/x86_64-linux-gnu/security/pam_ldap.so 2 | account required /lib/x86_64-linux-gnu/security/pam_ldap.so 3 | 4 | -------------------------------------------------------------------------------- /nginx-yum-repo/rebuild-repo.path: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description= Rebuild repo 3 | 4 | [Path] 5 | PathModified=/srv/data/repoflags 6 | 7 | [Install] 8 | WantedBy=multi-user.target 9 | -------------------------------------------------------------------------------- /ssl-certs/gen_csr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | openssl req -new -newkey rsa:2048 -config $1.csr.conf -nodes -keyout $1.key -out $1.csr 4 | 5 | openssl req -in $1.csr -noout -text 6 | -------------------------------------------------------------------------------- /nginx-yum-repo/rebuild-repo.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description= Rebuild repo 3 | 4 | [Service] 5 | Type=oneshot 6 | User=nginx 7 | Group=nginx 8 | ExecStart=/opt/bin/rebuild_repo.sh 9 | -------------------------------------------------------------------------------- /nginx-google-authenticator/etc/pam.d/nginx_google: -------------------------------------------------------------------------------- 1 | auth required pam_google_authenticator.so secret=/etc/nginx/gauth/${USER} user=nginx 2 | account required pam_permit.so 3 | -------------------------------------------------------------------------------- /nginx-google-authenticator/createuser.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | USER=$1 3 | google-authenticator -t -l "${USER} at my.web.site" -D -f -u -w 10 -s /etc/nginx/gauth/${USER} 4 | chown nginx:nginx /etc/nginx/gauth/${USER} 5 | -------------------------------------------------------------------------------- /nginx-AD-auth/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | server { 3 | listen 80 ; 4 | 5 | auth_pam "Secure Zone"; 6 | auth_pam_service_name "nginx"; 7 | 8 | location / { return 200 "Authorized" ; } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /nginx-stream-ssh/ssh_config: -------------------------------------------------------------------------------- 1 | Host * 2 | ProxyCommand openssl s_client -quiet -connect %h:22 2>/dev/null 3 | 4 | # Host * 5 | # ProxyCommand openssl s_client -quiet -connect %h:22 -cert client.cert -key client.key 2>/dev/null 6 | -------------------------------------------------------------------------------- /ssl-certs/check_expire.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | domain=$1 4 | 5 | /bin/date --utc --date "$(echo "Q" | openssl s_client -connect ${domain}:443 -servername ${domain} 2>/dev/null | openssl x509 -noout -enddate | awk -F'=' '{print $2}' )" 6 | -------------------------------------------------------------------------------- /nginx-google-authenticator/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | load_module modules/ngx_http_auth_pam_module.so ; 3 | 4 | # ... 5 | 6 | location / { 7 | auth_pam "Secure Zone"; 8 | auth_pam_service_name "nginx_google"; 9 | # ... 10 | } 11 | 12 | -------------------------------------------------------------------------------- /nginx-shell-webhook/shell-webhook.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=socat-based cmd api 3 | After=network.target 4 | 5 | [Service] 6 | User=nobody 7 | Group=nobody 8 | ExecStart=/usr/bin/socat UDP-LISTEN:50333,fork,bind=127.0.0.1 EXEC:/opt/bin/shell-webhook 9 | Restart=always 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /error-code-status/lua/status_code_log.lua: -------------------------------------------------------------------------------- 1 | local status_codes = ngx.shared.status_codes 2 | 3 | local resp_code = tonumber(ngx.var.status) 4 | 5 | local newval, err = status_codes:incr(resp_code, 1) 6 | if not newval and err == "not found" then 7 | status_codes:add(resp_code, 0) 8 | status_codes:incr(resp_code, 1) 9 | end 10 | -------------------------------------------------------------------------------- /nginx-shell-webhook/nginx.conf: -------------------------------------------------------------------------------- 1 | http { 2 | 3 | log_format shellwebhook '$cmd\n' ; 4 | 5 | 6 | server { 7 | location ~* ^/cmd/(\w+)$ { 8 | set $cmd $1 ; 9 | return 200 "$cmd"; 10 | access_log syslog:server=127.0.0.1:50333,facility=local7,tag=nginx,severity=info,nohostname shellwebhook ; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ssl-certs/gen_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | openssl req -new -newkey rsa:2048 -text -out cert.req -days 730 4 | openssl rsa -in privkey.pem -out cert.pem 5 | openssl req -x509 -in cert.req -text -key cert.pem -out cert.cert -days 730 6 | openssl dhparam -out dhparams.pem 2048 7 | 8 | cp cert.pem $1.key 9 | cp cert.cert $1.cert 10 | 11 | rm cert.* privkey* 12 | 13 | -------------------------------------------------------------------------------- /nginx-shell-webhook/shell-webhook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LOG=/var/log/shell-webhook.log 4 | 5 | declare -a DATA 6 | read -a DATA 7 | cmd=${DATA[4]} 8 | 9 | case ${cmd} in 10 | 11 | reboot) 12 | echo "Executing reboot" >> ${LOG} 13 | ;; 14 | 15 | update) 16 | echo "Executing update" >> ${LOG} 17 | ;; 18 | 19 | *) 20 | echo "Unknown command" >> ${LOG} 21 | ;; 22 | 23 | esac 24 | -------------------------------------------------------------------------------- /ssl-certs/gen_client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | openssl req -new -newkey rsa:2048 -text -out cert.req -days 730 4 | openssl rsa -in privkey.pem -out cert.pem 5 | openssl req -x509 -in cert.req -text -key cert.pem -out cert.cert -days 730 6 | openssl pkcs12 -export -in cert.cert -inkey cert.pem -out cert.p12 7 | 8 | cp cert.cert $1.client.cert 9 | cp cert.p12 $1.client.p12 10 | 11 | rm cert.* privkey* 12 | 13 | -------------------------------------------------------------------------------- /nginx-yum-repo/rebuild_repo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FLAGPATH="/srv/data/repoflags" 4 | REPOPATH="/srv/data/repo" 5 | VALID_REPOS=" $(ls -ld ${REPOPATH}/* | xargs -n1 basename | xargs echo ) " 6 | 7 | for flag in ${FLAGPATH}/* 8 | do 9 | repo=$(basename ${flag}) 10 | 11 | if [[ ${VALID_REPOS} == *" ${repo} "* ]]; then 12 | /bin/createrepo_c --update ${REPOPATH}/${repo} 13 | fi 14 | 15 | rm -f ${flag} 16 | done 17 | -------------------------------------------------------------------------------- /error-code-status/lua/status_code_dump.lua: -------------------------------------------------------------------------------- 1 | local status_codes = ngx.shared.status_codes 2 | local notfound = status_codes:get("404") or 0 3 | local badgateway = status_codes:get("502") or 0 4 | local gatewaytimeout = status_codes:get("504") or 0 5 | local clienterr = status_codes:get("499") or 0 6 | local total = badgateway + gatewaytimeout 7 | 8 | ngx.say(notfound, " " , clienterr , " " , badgateway, " " , gatewaytimeout , " = ", total) 9 | -------------------------------------------------------------------------------- /nginx-dumb-mertics/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module modules/ngx_http_xslt_filter_module.so; 2 | 3 | log_format metrics "" ; 4 | 5 | server { 6 | listen 80 ; 7 | access_log /tmp/nginx_metrics/code_$status metrics ; 8 | 9 | location / { 10 | root html ; 11 | } 12 | 13 | location /nginx_metrics { 14 | alias /tmp/nginx_metrics ; 15 | autoindex on ; 16 | autoindex_format xml ; 17 | xslt_stylesheet /tmp/nginx_metrics/.style/metrics.xslt ; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /nginx-dumb-mertics/nginx_metrics/.style/metrics.xslt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | nginx_dumb_requests{metric=""} 6 | 7 | 8 | -------------------------------------------------------------------------------- /metrics-aggregation/status.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 0.0.0.0:12345 ; 3 | access_log /dev/null; 4 | 5 | location /metrics { 6 | allow 127.0.0.1/32 ; 7 | deny all ; 8 | ssi on ; 9 | ssi_types text/plain ; 10 | return 200 11 | ' 12 | ' ; 13 | 14 | } 15 | 16 | location /vts { 17 | internal ; 18 | vhost_traffic_status_display; 19 | vhost_traffic_status_display_format prometheus ; 20 | } 21 | 22 | location /node { 23 | internal ; 24 | proxy_pass http://127.0.0.1:9100/metrics ; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /nginx-AD-auth/etc/pam_ldap.conf: -------------------------------------------------------------------------------- 1 | host 192.168.0.1 2 | base dc=org,dc=domain,dc=com 3 | 4 | ldap_version 3 5 | 6 | binddn webserver 7 | bindpw qwerty1234 8 | 9 | scope sub 10 | timelimit 5 11 | bind_timelimit 5 12 | referrals no 13 | 14 | pam_lookup_policy yes 15 | 16 | # RFC 2307 (AD) mappings 17 | nss_map_objectclass posixAccount user 18 | nss_map_objectclass shadowAccount user 19 | nss_map_attribute uid sAMAccountName 20 | nss_map_attribute homeDirectory unixHomeDirectory 21 | nss_map_attribute shadowLastChange pwdLastSet 22 | nss_map_objectclass posixGroup group 23 | nss_map_attribute uniqueMember member 24 | pam_login_attribute sAMAccountName 25 | pam_filter objectclass=User 26 | pam_password ad 27 | 28 | uri ldap://192.168.0.1 29 | ssl no 30 | pam_password md5 31 | 32 | -------------------------------------------------------------------------------- /ssl-certs/nginx-client-cert.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | 4 | listen 443 ssl ; 5 | listen [::]:443 ssl ; 6 | 7 | ssl_certificate ssl/host.tld.cert; 8 | ssl_certificate_key ssl/host.tld.key; 9 | ssl_client_certificate ssl/host.tld.client.cert ; 10 | ssl_dhparam ssl/dhparams.pem; 11 | 12 | ssl_verify_client on; 13 | ssl_verify_depth 1; 14 | 15 | ssl_session_cache shared:SSL:10m; 16 | ssl_session_timeout 10m; 17 | 18 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 19 | ssl_prefer_server_ciphers on; 20 | 21 | ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS; 22 | 23 | add_header Strict-Transport-Security "max-age=31536000;"; 24 | 25 | location / { 26 | return 200 "SSL client accepted"; 27 | } 28 | 29 | } 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ssl-certs/host.tld.csr.conf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | default_keyfile = privkey.pem 4 | distinguished_name = req_distinguished_name 5 | req_extensions = req_ext 6 | 7 | [ req_distinguished_name ] 8 | countryName = Country Name (2 letter code) 9 | countryName_default = RU 10 | stateOrProvinceName = State or Province Name (full name) 11 | stateOrProvinceName_default = Russian Federation 12 | localityName = Locality Name (eg, city) 13 | localityName_default = Moscow 14 | organizationName = Organization Name (eg, company) 15 | organizationName_default = Ajax, inc. 16 | organizationalUnitName = Organization Name (eg, company) 17 | organizationalUnitName_default = IT 18 | commonName = Common Name (eg, YOUR name) 19 | commonName_default = host.tld 20 | commonName_max = 64 21 | 22 | [ req_ext ] 23 | subjectAltName = @alt_names 24 | 25 | [alt_names] 26 | DNS.1 = mail.host.tld 27 | DNS.2 = www.host.tld 28 | -------------------------------------------------------------------------------- /nginx-yum-repo/yum-repo.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80 default; 4 | 5 | server_name yum.repo.tld ; 6 | 7 | access_log /dev/null combined_plus ; 8 | error_log /dev/null ; 9 | 10 | root /srv/data ; 11 | 12 | location / { return 200 "Yum repository"; } 13 | 14 | location ~* "^/repoflags/([^/]+)$" { 15 | proxy_pass http://127.0.0.1:18080 ; 16 | proxy_store /srv/data/repoflags/$1; 17 | proxy_store_access user:rw group:rw all:r; 18 | } 19 | 20 | location ~* ^/repo/(.+)\.rpm$ { 21 | dav_methods PUT ; 22 | create_full_put_path on; 23 | dav_access group:rw all:r; 24 | } 25 | 26 | location /repo/ { 27 | autoindex on; 28 | } 29 | 30 | } 31 | 32 | ####### yum cacher ###### 33 | 34 | ####### empty ###### 35 | server { 36 | listen 127.0.0.1:18080; 37 | access_log /dev/null combined_plus; 38 | error_log /dev/null ; 39 | 40 | location / { try_files $uri @empty; } 41 | location @empty { return 200 "oIo"; } 42 | } 43 | ####### empty ###### 44 | -------------------------------------------------------------------------------- /http-session/rsyslog.local.conf: -------------------------------------------------------------------------------- 1 | $MaxMessageSize 64k 2 | $WorkDirectory /tmp 3 | $EscapeControlCharactersOnReceive off 4 | $umask 0000 5 | 6 | module(load="imtcp" ) 7 | input(type="imtcp" port="12345" ruleset="httpsession") 8 | 9 | template(name="HTTP" 10 | type="string" 11 | string="%rawmsg%\n") 12 | 13 | template(name="session" type="list") { 14 | constant(value="/srv/logs/http_session.") 15 | property(name="timegenerated" dateFormat="rfc3339" position.from="1" position.to="10") 16 | constant(value=".log") 17 | } 18 | 19 | ruleset(name="httpsession") { 20 | 21 | *.* 22 | action( 23 | type="omfwd" 24 | Target="remote.log.collector" 25 | Port="11514" 26 | Protocol="tcp" 27 | Template="HTTP" 28 | TCP_Framing="octet-counted" ) 29 | 30 | action( 31 | type="omfile" 32 | dirCreateMode="0750" 33 | fileCreateMode="0644" 34 | Template="HTTP" 35 | DynaFile="session" ) 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /nginx-stream-ssh/nginx.conf: -------------------------------------------------------------------------------- 1 | stream { 2 | 3 | # 4 | ### Example mapping on client certificate's DN 5 | # 6 | # map $ssl_client_s_dn $ssh_client { 7 | # 8 | # "O=Internet Widgits Pty Ltd,ST=Some-State,C=AU" "OK" ; 9 | # default "NOT OK"; 10 | # 11 | # } 12 | # 13 | 14 | server { 15 | 16 | listen 22 ssl ; 17 | 18 | ssl_certificate /etc/nginx/ssl/domain.tld.cert; 19 | ssl_certificate_key /etc/nginx/ssl/domain.tld.key; 20 | ssl_dhparam /etc/nginx/ssldhparams.pem; 21 | 22 | # 23 | ### Enable this for client certificate authorization 24 | # 25 | # ssl_client_certificate /etc/nginx/ssl/domain.tld.client.cert ; 26 | # ssl_verify_client on; 27 | # 28 | 29 | ssl_verify_depth 1; 30 | 31 | ssl_session_cache shared:SSH:10m; 32 | ssl_session_timeout 10m; 33 | 34 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 35 | ssl_prefer_server_ciphers on; 36 | 37 | ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS; 38 | 39 | proxy_responses 1; 40 | proxy_timeout 5m; 41 | proxy_pass 127.0.0.1:8022 ; 42 | 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /nginx-extended-limit_rate/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes auto; 2 | 3 | error_log logs/error.log warn; 4 | pid logs/nginx.pid; 5 | 6 | events { 7 | worker_connections 8192; 8 | } 9 | 10 | http { 11 | include mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log logs/access.log main; 19 | 20 | sendfile on; 21 | 22 | keepalive_timeout 3; 23 | 24 | lua_shared_dict ips_limit 10m; 25 | 26 | init_by_lua_block { 27 | ips_limit = ngx.shared.ips_limit 28 | } 29 | 30 | 31 | server { 32 | listen 80 ; 33 | 34 | access_log /dev/null ; 35 | 36 | set $rate 5; # number of requests within $expire seconds 37 | set $expire 5; # expiration time, in seconds 38 | 39 | location / { 40 | 41 | access_by_lua_block { 42 | local ip = ngx.var.remote_addr 43 | local expire = tonumber(ngx.var.expire) 44 | local rate = tonumber(ngx.var.rate) 45 | local lim, flags = ips_limit:get(ip) 46 | if not lim then 47 | ips_limit:set(ip, 1, expire) 48 | return 49 | elseif lim < rate then 50 | ips_limit:incr(ip,1) 51 | else 52 | ngx.exit(ngx.HTTP_FORBIDDEN) 53 | end 54 | } 55 | 56 | 57 | } 58 | 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /error-code-status/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | user nginx; 3 | worker_processes auto; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | load_module modules/ngx_http_lua_module.so ; 9 | 10 | worker_rlimit_nofile 32768 ; 11 | 12 | events { 13 | use epoll ; 14 | worker_connections 16384; 15 | } 16 | 17 | 18 | http { 19 | include /etc/nginx/mime.types; 20 | default_type application/octet-stream; 21 | 22 | log_format combined_plus '$remote_addr - $remote_user [$time_local]' 23 | ' "$request" $status $body_bytes_sent "$http_referer"' 24 | ' "$http_user_agent" $request_time $upstream_cache_status' 25 | ' [$upstream_response_time]'; 26 | 27 | access_log /var/log/nginx/access.log combined_plus; 28 | 29 | 30 | lua_shared_dict status_codes 1M; 31 | lua_shared_dict urls 4M; 32 | log_by_lua_file /etc/nginx/lua/status_code_log.lua ; 33 | 34 | 35 | sendfile on; 36 | #tcp_nopush on; 37 | 38 | #keepalive_timeout 0; 39 | keepalive_timeout 65; 40 | 41 | gzip on; 42 | 43 | 44 | index index.html index.htm; 45 | 46 | include /etc/nginx/conf.d/*.conf; 47 | 48 | server { 49 | listen 127.0.0.1:80 ; 50 | access_log /dev/null; 51 | 52 | location / { 53 | stub_status on; 54 | } 55 | 56 | location = /codes { 57 | content_by_lua_file /etc/nginx/lua/status_code_dump.lua ; 58 | } 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /lua-ffi/nginx.qrencode.conf: -------------------------------------------------------------------------------- 1 | 2 | init_by_lua_block { 3 | 4 | ffi = require("ffi") 5 | libqrencode = ffi.load("libqrencode.so.3") 6 | 7 | BLACK="⬛️" 8 | WHITE="⬜️" 9 | 10 | ffi.cdef[[ 11 | 12 | typedef enum { 13 | QR_ECLEVEL_L = 0, 14 | QR_ECLEVEL_M, 15 | QR_ECLEVEL_Q, 16 | QR_ECLEVEL_H 17 | } QRecLevel; 18 | 19 | typedef struct { 20 | int version; 21 | int width; 22 | unsigned char *data; 23 | } QRcode; 24 | 25 | QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level); 26 | 27 | ]] 28 | 29 | } 30 | 31 | server { 32 | listen 80; 33 | 34 | access_log /dev/null ; 35 | 36 | location / { 37 | charset utf8; 38 | default_type text/html; 39 | set $string "$scheme://$http_host$request_uri"; 40 | content_by_lua_block { 41 | 42 | local qr = ffi.new("QRcode[?]",0) 43 | local STRING=ngx.var.string 44 | 45 | qr = libqrencode.QRcode_encodeString8bit(STRING,0,0) 46 | local width = qr.width 47 | local data = ffi.string(qr.data, width*width) 48 | qr = nil 49 | 50 | out = '
\n\n'
51 | 
52 | local i = 0
53 | for cur = 1, #data do
54 |     local c = data:byte(cur, cur)
55 |     char = (bit.band(c,1) == 0)  and WHITE or BLACK
56 |     out = out .. char
57 |     i = i + 1
58 | 
59 |     if i == width then
60 |       out = out .. "\n"
61 |       i = 0
62 |     end
63 | end
64 | 
65 | out = out .. "\n\n
" 66 | 67 | ngx.say(out) 68 | 69 | 70 | } 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /nginx-autoban/server.conf: -------------------------------------------------------------------------------- 1 | ### Rate limiting 2 | limit_req_zone $binary_remote_addr zone=api_limit:64m rate=10r/m ; 3 | 4 | ### Lua blocker 5 | lua_shared_dict banned_ips 32m ; 6 | 7 | init_by_lua_block { 8 | 9 | banned_ips = ngx.shared.banned_ips 10 | 11 | } 12 | 13 | ### server.com 14 | 15 | server { 16 | 17 | listen 0.0.0.0:80 ; 18 | 19 | server_name server.com ; 20 | 21 | ### check if client is banned 22 | access_by_lua_block { 23 | 24 | local ip = ngx.var.remote_addr 25 | local ban, flags = banned_ips:get(ip) 26 | if ban then 27 | ngx.exit(ngx.HTTP_FORBIDDEN) 28 | else 29 | return 30 | end 31 | 32 | } 33 | 34 | ### location to ban 35 | 36 | location @ban { 37 | content_by_lua_block { 38 | 39 | local ip = ngx.var.remote_addr 40 | local expire = 300 # time to ban client's ip, in seconds. 41 | local ban, flags = banned_ips:get(ip) 42 | if not ban then 43 | banned_ips:set(ip, 1, expire) 44 | ngx.exit(ngx.HTTP_FORBIDDEN) 45 | end 46 | 47 | } 48 | } 49 | 50 | ### Protected locations 51 | 52 | location /login { 53 | limit_req zone=api_limit burst=2 nodelay; 54 | error_page 503 @ban ; 55 | proxy_pass http://127.0.0.1:8080 ; # backend endpoint 56 | } 57 | 58 | ### Other locations 59 | 60 | location / { 61 | proxy_pass http://127.0.0.1:8080 ; 62 | } 63 | 64 | ### Metrics and statistics 65 | 66 | location /ban_count { 67 | content_by_lua_block { 68 | local ips = banned_ips:get_keys(0) 69 | ngx.say("nginx_lua_blocked_ips " .. table.getn(ips) .. "\n") 70 | } 71 | } 72 | 73 | location /ban_dump { 74 | allow 127.0.0.1/32 ; 75 | deny all ; 76 | content_by_lua_block { 77 | 78 | local ips = banned_ips:get_keys(0) 79 | local output = "" 80 | for k,v in pairs(ips) do 81 | output = output .. v .. "\n" 82 | end 83 | ngx.say(output) 84 | 85 | } 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /http-session/nginx.proxy.conf: -------------------------------------------------------------------------------- 1 | 2 | user nginx; 3 | worker_processes auto; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | load_module modules/ngx_http_lua_module.so ; 9 | 10 | worker_rlimit_nofile 32768 ; 11 | 12 | events { 13 | use epoll ; 14 | worker_connections 16384; 15 | } 16 | 17 | 18 | http { 19 | include /etc/nginx/mime.types; 20 | default_type application/octet-stream; 21 | 22 | log_format combined_plus '$remote_addr - $remote_user [$time_local]' 23 | ' "$request" $status $body_bytes_sent "$http_referer"' 24 | ' "$http_user_agent" $request_time $upstream_cache_status' 25 | ' [$upstream_response_time]'; 26 | 27 | access_log /var/log/nginx/access.log combined_plus; 28 | 29 | 30 | lua_need_request_body on ; 31 | 32 | init_worker_by_lua_block { 33 | 34 | socket = require("socket") 35 | tcp = assert(socket.tcp()) 36 | assert(tcp:connect("127.0.0.1", 11515)) 37 | 38 | } 39 | 40 | sendfile on; 41 | #tcp_nopush on; 42 | 43 | #keepalive_timeout 0; 44 | keepalive_timeout 65; 45 | 46 | gzip on; 47 | 48 | client_max_body_size 128m ; 49 | 50 | index index.html index.htm; 51 | 52 | upstream remoteserver { 53 | server 1.2.3.4:80 ; 54 | } 55 | 56 | 57 | server { 58 | 59 | listen 127.0.0.1:8080 default ; 60 | 61 | server_name logging.proxy ; 62 | 63 | access_log /dev/null ; 64 | 65 | location / { 66 | 67 | set $req_headers ""; 68 | set $req_body ""; 69 | set $resp_headers ""; 70 | set $resp_body ""; 71 | 72 | rewrite_by_lua_block { 73 | 74 | local method = ngx.var.request_method 75 | ngx.req.read_body() 76 | ngx.var.req_body = ngx.req.get_body_data() 77 | 78 | } 79 | 80 | body_filter_by_lua_block { 81 | 82 | local resp_body = string.sub(ngx.arg[1], 1, -1) 83 | ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body 84 | if ngx.arg[2] then 85 | ngx.var.resp_body = ngx.ctx.buffered 86 | end 87 | 88 | local req_h = "" 89 | for k,v in pairs (ngx.req.get_headers()) do 90 | req_h = req_h .. k .. ": " .. v .. "\n" 91 | end 92 | ngx.var.req_headers = req_h 93 | 94 | local resp_h = "" 95 | for k,v in pairs (ngx.resp.get_headers()) do 96 | resp_h = resp_h .. k .. ": " .. v .. "\n" 97 | end 98 | ngx.var.resp_headers = resp_h 99 | 100 | } 101 | 102 | log_by_lua_block { 103 | 104 | local out = "===== " .. tostring(ngx.var.time_local) .. " ====\n" 105 | out = out .. tostring(ngx.var.request) .. "\n==\n" .. tostring(ngx.var.req_headers) .. "\n==\n" .. tostring(ngx.var.req_body) .. "\n==\n" 106 | out = out .. "HTTP " .. tostring(ngx.var.status) .. "\n==\n" .. tostring(ngx.var.resp_headers) .. "\n==\n" .. tostring(ngx.var.resp_body) 107 | out = out .. "\n=====================================\n=\n=\n=\n" 108 | assert(tcp:send(out)) 109 | 110 | } 111 | 112 | 113 | 114 | proxy_pass http://remoteserver; 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /nginx-modules/build-modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Build environment 4 | # 5 | # Debian 9: apt-get install curl make gcc g++ uuid-dev libdpkg-perl luajit libluajit-5.1-dev libpcre3-dev libssl-dev libz-dev libpam0g-dev 6 | # 7 | 8 | 9 | function spinner() { 10 | i=1 11 | sp="/-\|" 12 | echo -n ' ' 13 | while read line 14 | do 15 | printf "\b${sp:i++%${#sp}:1}" 16 | done 17 | echo 18 | } 19 | 20 | VER=$(nginx -V 2>&1 ) 21 | TMP=$(mktemp -d) 22 | HOMEDIR=$(pwd) 23 | 24 | 25 | if [ "$(uname -m)" = x86_64 ]; then 26 | BIT_SIZE_NAME=x64 27 | else 28 | BIT_SIZE_NAME=ia32 29 | fi 30 | 31 | VERSION=$(echo "${VER}" | grep "^nginx version: " | awk -F 'nginx version: nginx/' '{print $2}') 32 | CONFIGURE=$(echo "${VER}" | grep "^configure arguments: " | awk -F 'configure arguments: ' '{print $2}' | sed -r ' 33 | s/([^\ ]*=dynamic )/ /g; 34 | s/ --add-dynamic-module=([^\ ]+) / /g; 35 | s/ --add-module=([^\ ]+) / /g;') 36 | 37 | SRC="nginx-${VERSION}" 38 | SRCFILE="nginx-${VERSION}.tar.gz" 39 | 40 | MODULES_PATH="${HOMEDIR}/nginx-${VERSION}-modules" 41 | mkdir -p ${MODULES_PATH} 42 | 43 | pushd ${TMP} 44 | 45 | curl -# http://nginx.org/download/${SRCFILE} > ${SRCFILE} 46 | 47 | ### Clone repos 48 | 49 | git clone https://github.com/vozlt/nginx-module-vts.git nginx-module-vts 50 | git clone https://github.com/sto/ngx_http_auth_pam_module.git ngx_http_auth_pam_module 51 | git clone https://github.com/vkholodkov/nginx-eval-module.git nginx-eval-module 52 | git clone https://github.com/aperezdc/ngx-fancyindex.git ngx-fancyindex 53 | git clone https://github.com/arut/nginx-rtmp-module.git nginx-rtmp-module 54 | git clone https://github.com/vozlt/nginx-module-url.git nginx-module-url 55 | git clone https://github.com/kaltura/nginx-vod-module.git nginx-vod-module 56 | 57 | git clone https://github.com/openresty/lua-nginx-module.git lua-nginx-module 58 | git clone https://github.com/openresty/lua-upstream-nginx-module.git lua-upstream-nginx-module 59 | git clone https://github.com/openresty/stream-lua-nginx-module.git stream-lua-nginx-module 60 | git clone https://github.com/openresty/headers-more-nginx-module.git headers-more-nginx-module 61 | git clone https://github.com/openresty/encrypted-session-nginx-module.git encrypted-session-nginx-module 62 | 63 | git clone https://github.com/yaoweibin/ngx_http_substitutions_filter_module.git ngx_http_substitutions_filter_module 64 | 65 | 66 | ### Openresty's cross-dependencies 67 | git clone https://github.com/openresty/set-misc-nginx-module.git set-misc-nginx-module 68 | git clone https://github.com/vision5/ngx_devel_kit.git ngx_devel_kit 69 | 70 | 71 | ### Modules with extra configuration 72 | git clone https://github.com/pagespeed/ngx_pagespeed.git ngx_pagespeed 73 | git clone https://github.com/google/ngx_brotli.git ngx_brotli 74 | 75 | 76 | ### Prepare repos 77 | 78 | ( cd lua-nginx-module ; git checkout tags/v0.10.15 ; cd .. ) 79 | ( cd stream-lua-nginx-module ; git checkout tags/v0.0.7 ; cd .. ) 80 | ( cd ngx_pagespeed ; git checkout tags/latest-stable ; cd .. ) 81 | # ( cd set-misc-nginx-module ; git checkout tags/v0.32 ; cd .. ) 82 | 83 | ### Prepare dependencies 84 | 85 | ( cd ngx_brotli ; git submodule update --init ; cd .. ) 86 | 87 | ( cd ngx_pagespeed 88 | 89 | _psol=$( cat PSOL_BINARY_URL ) 90 | PSOL_URL=$( eval "echo ${_psol}" ) 91 | curl -# "${PSOL_URL}" > psol.tar.gz 92 | tar zxf psol.tar.gz 93 | 94 | cd .. ) 95 | 96 | tar zxf ${SRCFILE} 97 | cd ${SRC} 98 | CMD="./configure ${CONFIGURE} \ 99 | --add-dynamic-module=../lua-nginx-module \ 100 | --add-dynamic-module=../lua-upstream-nginx-module \ 101 | --add-dynamic-module=../nginx-module-vts \ 102 | --add-dynamic-module=../ngx_http_auth_pam_module \ 103 | --add-dynamic-module=../ngx_brotli \ 104 | --add-dynamic-module=../ngx_pagespeed \ 105 | --add-dynamic-module=../ngx_devel_kit \ 106 | --add-dynamic-module=../set-misc-nginx-module \ 107 | --add-dynamic-module=../encrypted-session-nginx-module \ 108 | --add-dynamic-module=../nginx-eval-module \ 109 | --add-dynamic-module=../ngx-fancyindex \ 110 | --add-dynamic-module=../nginx-rtmp-module \ 111 | --add-dynamic-module=../nginx-module-url \ 112 | --add-dynamic-module=../headers-more-nginx-module \ 113 | --add-dynamic-module=../nginx-vod-module \ 114 | --add-dynamic-module=../ngx_http_substitutions_filter_module \ 115 | --add-dynamic-module=../stream-lua-nginx-module \ 116 | " 117 | 118 | 119 | eval ${CMD} 120 | 121 | ( make | spinner ) && cp objs/*.so ${MODULES_PATH} 122 | #( make | spinner ) && ls -l objs/*.so 123 | 124 | popd 125 | 126 | ls -l ${MODULES_PATH}/ 127 | 128 | # echo ${TMP} 129 | rm -rf ${TMP} 130 | 131 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # Nginx usecases 2 | 3 | ## http-session 4 | 5 | nginx/syslog-based HTTP-sniffer. Prerequisites: 6 | - lua-nginx-module 7 | - luasocket available under builtin luajit 8 | 9 | ## error-code-status 10 | 11 | Simple lua-based extended status, logging errors by http response code - to use with zabbix, etc. Requires lua-nginx-module 12 | 13 | ## metrics-aggregation 14 | 15 | Aggregate prometheus metrics from different exporters in a single endpoint. 16 | 17 | ## nginx-AD-auth 18 | 19 | nginx http-auth against Microsoft Active Directory. 20 | In most cases, foreign soft authenticates against AD using LDAP. So nginx got it's own auth_ldap module - but in some complicated AD schemas it doesn't work at all. 21 | The key point is to use [ngx_auth_pam](https://github.com/sto/ngx_http_auth_pam_module), and set bindings to AD in pam. 22 | 23 | ## nginx-google-authenticator 24 | 25 | nginx with OTP by Google Authenticator. 26 | The key point is also to use [ngx_auth_pam](https://github.com/sto/ngx_http_auth_pam_module). 27 | Install Google Authenticator pam-module: 28 | ``` 29 | apt-get install libpam-google-authenticator 30 | ``` 31 | 32 | Create pam service config (etc/pam.d/nginx_google), and produce GAs files like this: 33 | ``` 34 | createuser.sh johndoe 35 | ``` 36 | ## nginx-dumb-metrics 37 | 38 | Minimalistic prometheus metrics exporter build on top on vanilla nginx with no external modules. Sample output: 39 | ``` 40 | nginx_dumb_requests{metric="code_200"} 14 41 | nginx_dumb_requests{metric="code_404"} 1 42 | nginx_dumb_requests{metric="up"} 1 43 | ``` 44 | 45 | Note: file `up` is required to satisfy xml parser. 46 | 47 | ## ssl-certs 48 | 49 | A bunch of scripts to generate self-signed SSL certs, client .p12 certs, and csr's with SAN. 50 | 51 | gen_server.sh - creates self-signed cert/key and DH-params file. 52 | ``` 53 | ./gen_server.sh host.tld 54 | 55 | ``` 56 | 57 | gen_client.sh - creates client .p12 cert to use with certificate authentication. Usage example shown in nginx-client-cert.conf 58 | ``` 59 | ./gen_client.sh host.tld 60 | 61 | ``` 62 | Note, that it's possible to use self-signed client certs with a host cert, signed by any trusted CA. 63 | Also note, that a file set in ssl_client_certificate may contain several client certificates. Current client can be obtained from ngx_http_ssl_module embedded variables. 64 | 65 | gen_csr.sh - creates CSR with SAN for trusted CA and dumps csr content in readable form. 66 | ``` 67 | ./gen_csr.sh host.tld 68 | 69 | ``` 70 | SAN, for example, is required by several CA's to create a wildcard cert. Alternative namess should be defined in host.tld.csr.conf among pre-defined defautls. 71 | When CA requires csr with SAN for wildcard - in most cases you should define main CN as *.host.tld, and first alternative name set to host.tld. 72 | 73 | check_expire.sh - checks a cert's expiration date on a remote host (using GNU date, so keep in mind). 74 | ``` 75 | $ ./check_expire.sh google.com 76 | Wed May 30 18:50:00 UTC 2018 77 | $ 78 | ``` 79 | 80 | ## nginx-modules 81 | 82 | An automated script to build additional dynamic modules for official nginx package. 83 | The script simply build modules for exact installed nginx version and places results into current directory. 84 | The script requires build environment to be set - including GCC, git, -devel packages for libraries, etc. 85 | 86 | Currently builds modules: 87 | 88 | - Nginx auth_pam module 89 | - Nginx brotli module 90 | - Nginx Lua module 91 | - Nginx Lua stream module (Note: working version of this module does not support dynamic builds) 92 | - Nginx Lua upstream module 93 | - Nginx pagespeed module 94 | - Nginx virtual host traffic status module 95 | - Nginx Development Kit module 96 | - Nginx encrypted sessions module 97 | - Nginx set misc module 98 | - Nginx memcache eval module 99 | - Nginx fancy index module 100 | - Nginx headers_more module 101 | - Nginx rtmp module 102 | - Nginx substitutions filter module 103 | - Nginx VOD module 104 | 105 | ## nginx-yum-repo 106 | 107 | Minimalistic setup to serve yum-repository with nginx. 108 | Requirements: 109 | 110 | - systemd 111 | - nginx 112 | - createrepo (or, for best performance - C implementation [createrepo_c](https://github.com/rpm-software-management/createrepo_c) 113 | 114 | RPM packages are pushed into repository via WebDAV, and, after all packages uploaded, one have to trigger rebuild by http hook. 115 | ``` 116 | curl -T package.rpm http://yum.repo.tld/repo/name/package.rpm 117 | curl http://yum.repo.tld/repoflag/name 118 | ``` 119 | 120 | In general, it's possible to remove hook, and rebuild repodata just on package upload - but, in busy CI environments it will be rebuilding too often. 121 | 122 | ## lua-ffi 123 | 124 | Example how to use luajit-ffi with nginx, based on libqrencode. 125 | First, calling shared library functions requires, that this particular library exists in nginx's process memory space. This could be done with several ways: 126 | 127 | - using native ffi.load() call; 128 | - linking library into nginx binary upon building (either statically or dynamically); 129 | - using LD_PRELOAD env variable; 130 | 131 | As a most complicated way, in this example ffi.load() is used, loading symbols into separate namespace "libqrencode". 132 | 133 | Then, one have to define all necessary symbols from a libqrencode with ffi.cdef() exactly as they're defined in qrencode.h. 134 | The rest is quite obvious except the point that *encode functions returns a pointer to array of chars with meaningful lowest bit - so we have to process this array in lua to draw an "image". 135 | 136 | If everything is ok, you should see something like this: 137 | 138 | ![sample qr-code](https://github.com/toxatoor/nginx/blob/master/lua-ffi/lua-qrencode.png) 139 | 140 | Note, that you're playing in deep water, and there can be leaks and other issues, causing nginx worker to segfault. 141 | Also note, that init_by_lua_* statements executed upon start master/worker process, and content_by_lua_* - upon accessing to the location, which causes re-reading code when content_by_lua_file is used. So you can run into state when different nginx workers uses different code; therefore in thes example *_by_lua_block is used. 142 | 143 | ## nginx-extended-limit_rate 144 | 145 | Extending limit_rate to any time window. 146 | 147 | ## nginx-autoban 148 | 149 | Lua-based auto blocker. Bans clients exceesing rate limit for arbitrary set time. Supports minimalistic metrics export, could be extended by adding unban option. 150 | Might also be extended to ban clients on any attribute available within HTTP session, e.g: user-agent, args, headers, cookies etc. 151 | 152 | ## nginx-stream-ssh 153 | 154 | Wrapping ssh connection into SSL using nginx-stream module. 155 | The configuration is quite simple: 156 | 157 | - bind sshd to 127.0.0.1:8022 using ListenAddress in sshd_config; 158 | - add stream section into nginx.conf; 159 | - add Host configuration into ssh_config (or ~/.ssh/config); 160 | 161 | This could be used for extra: 162 | 163 | Security 164 | 165 | - most scanning bots expects ssh handshake on 22/tcp, so they will be confused; 166 | - adding a client certificate authentication could add a sort of second factor; 167 | 168 | Flexibility 169 | 170 | - as nginx read SSL session date before proxing, it's possible to proxy a single entry point ssh connections to different upstream by SNI, client certificate DN, issue/expiration date, serial etc using variable mapping. Adding lua scripting allows to use extremaly flexible dynamic mappings. 171 | 172 | ## nginx-shell-webhook 173 | 174 | Minimalistic approach to create shell-based webhooks accessable via nginx 175 | --------------------------------------------------------------------------------