https://gist.github.com/corburn/9ad9d07535d59b478159
Adjusting child processes for PHP-FPM (Nginx)
Sumario
Permitir underscore/guion bajo en headers
https://stackoverflow.com/questions/19751313/forward-request-headers-from-nginx-proxy-server
https://stackoverflow.com/questions/22856136/why-underscores-are-forbidden-in-http-header-names
underscores_in_headers on;
Permitir muchos server_name
https://nginx.org/en/docs/http/server_names.html
https://nginx.org/en/docs/hash.html
Al utilizar muchos server_name, puede llegar a aparecer cualquiera de estos dos errores:
could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32 could not build the server_names_hash, you should increase either server_names_hash_max_size: 512 or server_names_hash_bucket_size: 32
Esto se resuelve aumentando el tamaño de la tabla de hash:
server_names_hash_bucket_size 128; server_names_hash_max_size 4096;
Rate limit
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req
https://www.nginx.com/blog/rate-limiting-nginx/
https://www.freecodecamp.org/news/nginx-rate-limiting-in-a-nutshell-128fe9e0126c/
DNS resolver
https://distinctplace.com/2017/04/19/nginx-resolver-explained/
server { listen 80; server_name example.com; location / { resolver 172.16.0.23; set $upstream_endpoint http://service-999999.eu-west-2.elb.amazonaws.com; proxy_pass $upstream_endpoint$request_uri; } }
Generar configuracion
Location
http://nginx.org/en/docs/http/ngx_http_core_module.html#location
A location can either be defined by a prefix string, or by a regular expression. Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching). To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.
Confirmar regex
https://www.regextester.com/94055
Obtener IP de cliente detras de proxy
server { ... set_real_ip_from 10.0.0.0/8; real_ip_header X-Forwarded-For; ... }
Too many open files
https://www.scalescale.com/tips/nginx/nginx-accept-failed-24-too-many-open-files/#
Rewrite
https://www.nginx.com/blog/creating-nginx-rewrite-rules/
https://forum.nginx.org/read.php?2,213799,213799
Proxy
https://www.liaohuqiu.net/posts/nginx-proxy-pass/
En caso se que el puerto sea distinto, usar $http_host en lugar de $host:
location / { proxy_pass http://172.17.0.5:80; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
Location con diagonales y sin ellas
location ~ ^/phpmyadmin(?:/(.*))?$ { alias /home/phpmyadmin/$1; }
TCP Proxy
https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/
https://docs.nginx.com/nginx/admin-guide/security-controls/securing-tcp-traffic-upstream/
https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-tcp/
stream { log_format basic '$remote_addr [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time'; server { listen 8443; access_log /var/log/nginx/access.log basic; error_log /var/log/nginx/error.log; proxy_pass backend; proxy_ssl on allow 127.0.0.1; deny all; } upstream backend{ server myserver.com:8443; } }
FastCGI
Como probar FastCGI
- Configurar NGINX para que apunte a puerto de pruebas en el host deseado. En este ejemplo se usa 9001/TCP.
location / { root /var/www/html; include fastcgi_params; fastcgi_pass 10.0.0.1:9001; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_buffers 256 128k; fastcgi_connect_timeout 300s; fastcgi_send_timeout 300s; fastcgi_read_timeout 300s; }
- Iniciar un proceso de netcat escuchando en el mismo puerto y leer con strings la salida
# nc -l -p 9001 -v | strings listening on [any] 9001 ... connect to [10.0.0.1] from nginx-test [10.0.0.2] 48264 QUERY_STRING REQUEST_METHODGET CONTENT_TYPE CONTENT_LENGTH SCRIPT_NAME/test/test.php REQUEST_URI/test/test.php DOCUMENT_URI/test/test.php DOCUMENT_ROOT/var/www/html SERVER_PROTOCOLHTTP/1.1 REQUEST_SCHEMEhttp GATEWAY_INTERFACECGI/1.1 SERVER_SOFTWAREnginx/1.13.10 REMOTE_ADDR192.168.0.1 REMOTE_PORT5871 SERVER_ADDR10.0.0.2 SERVER_PORT80 SERVER_NAME REDIRECT_STATUS200 SCRIPT_FILENAME/var/www/html/test/test.php HTTP_HOSTwww.test.com:10080 HTTP_CONNECTIONkeep-alive HTTP_CACHE_CONTROLmax-age=0 HTTP_UPGRADE_INSECURE_REQUESTS1 UHTTP_ACCEPTtext/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 HTTP_ACCEPT_ENCODINGgzip, deflate HTTP_ACCEPT_LANGUAGEes-ES,es;q=0.9
Secure Link
https://www.nginx.com/blog/securing-urls-secure-link-module-nginx-plus/
Basic
Agregar lo siguiente a la configuracion de NGINX. Usando secure_link_secret y la clave enigma:
server { listen 80; server_name localhost; root /usr/share/nginx/html; location / { index index.html index.htm; } location /secret { secure_link_secret enigma; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } rewrite ^ /private/$secure_link; } location /private { internal; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
Para generar la clave:
SECRET=`echo -n 'secret/data.txtenigma777' | openssl md5 -hex | cut -d " " -f 2` curl -s http://192.168.0.1/secret/$SECRET/secret/data.txt
Expire
Agregar lo siguiente a la configuracion de NGINX. Usando secure_link_secret y la clave enigma:
server { listen 80; server_name localhost; root /usr/share/nginx/html; location / { index index.html index.htm; } location /private { secure_link $arg_md5,$arg_expires; secure_link_md5 "$secure_link_expires enigma"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
Agregar un script PHP con lo siguiente:
<?php /** * FROM: https://gist.github.com/bftanase/cbae1f9fc69bb4f9cb86 * @param $baseUrl - non protected part of the URL including hostname, e.g. http://example.com * @param $path - protected path to the file, e.g. /downloads/myfile.zip * @param $secret - the shared secret with the nginx server. Keep this info secure!!! * @param $ttl - the number of seconds until this link expires * @param $userIp - ip of the user allowed to download * @return string */ function buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp) { $expires = time() + $ttl; $md5 = md5("$expires $secret", true); $md5 = base64_encode($md5); $md5 = strtr($md5, '+/', '-_'); $md5 = str_replace('=', '', $md5); return $baseUrl . $path . '?md5=' . $md5 . '&expires=' . $expires; } // example usage $secret = 'enigma'; $baseUrl = 'http://<SERVER_IP'; $path = '/private/data.txt'; $ttl = 30; //no of seconds this link is active //$userIp = $_SERVER['REMOTE_ADDR']; $redirect = buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp); header("Location: $redirect"); die(); ?>
Python
- nginx:
server { listen 80; server_name _; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; root /usr/share/nginx/html; location / { index index.html index.htm; } location /insecure { autoindex on; alias /usr/share/nginx/html/media; } location /media { alias /usr/share/nginx/html/media; secure_link $arg_token; secure_link_md5 "$uri password"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
- python code
import hashlib import base64 secret = "password" media_uri = "/media/dir/data.txt" m = hashlib.md5() m.update("{uri} {secret}".format(uri=media_uri, secret=secret)) print(base64.b64encode(m.digest()).replace("+","-").replace("=",""))
- curl
curl http://example.com/media/dir/data.txt?token=tphEgJBcPqftoVRwT7YHsw
Python
- nginx:
server { listen 80; server_name _; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; root /usr/share/nginx/html; location / { index index.html index.htm; } location /insecure { autoindex on; alias /usr/share/nginx/html/media; } location /media { alias /usr/share/nginx/html/media; secure_link $arg_token; secure_link_md5 "$uri password"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
- python code
import hashlib import base64 secret = "password" media_uri = "/media/dir/data.txt" m = hashlib.md5() m.update("{uri} {secret}".format(uri=media_uri, secret=secret)) print(base64.b64encode(m.digest()).replace("+","-").replace("=",""))
- curl
curl http://example.com:8443/media/dir/data.txt?token=tphEgJBcPqftoVRwT7YHsw
Bash
- nginx:
server { listen 80; server_tokens off; root /usr/share/nginx/html; location / { index index.html index.htm; } location /secure { secure_link $arg_token,$arg_expires; secure_link_md5 "$secure_link_expires $uri enigma777"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
- bash:
Basado en http://nginx.2469901.n2.nabble.com/Cannot-get-secure-link-with-expires-to-work-td7604167.html
#!/bin/bash SECRET="enigma777" DURATION=60 URI="/secure/backup.tgz" SERVER="http://server.local:80" TOKEN_FORMAT="%s %s %s" # must match format of secure_link_md5 NOW=$( date +%s ) EXPIRES=$(( ${NOW} + ${DURATION} )) TOKEN=$(printf "${TOKEN_FORMAT}" ${EXPIRES} ${URI} ${SECRET} | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = ) URL="${SERVER}${URI}?token=${TOKEN}&expires=${EXPIRES}" curl ${URL}
Docker
Redireccion TCP
https://github.com/jetbrains-infra/docker-nginx-tcp-proxy