
Bueno ya hace unos meses publique el articulo de #SysAdmin – Asegurar nuestro server web nginx+let’s encrypt+securityheaders bueno después de unas cuantas configuraciones he optimizado mi código el cual comparto con ustedes. Actualmente he logrado la migración del lugares de algunos socios como: frcuba.cu, geocuba.cu, minjus.cu, gacetaoficial.cu, jovenclub.cu, uci.cu Espero que tu seas el proximo
Perfeccionado el Let’s Encrypt
Ubiquemos que tenemos una red donde la única pc que saldría directo a Internet seria el firewall, la misma tiene la función de proxy inverso.
A la hora de sacar el certificado hacemos lo siguiente
Instalación del Let’s Encrypt
1 2 3 | apt-get install git git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt cd /opt/letsencrypt |
Creación del certificado
Para la creación del mismo recomiendo no tener ningún servidor web funcionando en ese momento es decir tener libre el 80 y 443.
En este caso crear el certificado como para dominio.cu
1 2 3 | /etc/init.d/nginx stop /opt/letsencrypt/letsencrypt-auto certonly --standalone -d dominio.cu -d mail.dominio.cu -d smtp.dominio.cu -d pop.dominio.cu -d pop3.dominio.cu -d imap.dominio.cu -d www.dominio.cu -d webmail.dominio.cu -d proxy.dominio.cu -d download.dominio.cu -d openvpn.dominio.cu /etc/init.d/nginx start |
si se dan cuenta ahí hago referencia en a los dominios siguientes:
1 2 3 4 5 6 | dominio.cu <-- Dominio principal www.dominio.cu <-- Server Web download.dominio.cu <-- Web de Programas mail.dominio.cu webmail.dominio.cu pop.dominio.cu pop3.dominio.cu smtp.dominio.cu imap.dominio.cu <-- Server de Correo proxy.dominio.cu <-- Server Proxy openvpn.dominio.cu <-- Server Openvpn |
Esto es para que a la hora de crear los sitios y esas cosas puedas poner un único certificado en las configuraciones de nginx.
Transmitir el certificado a otro servidor
Creamos la llave ssh
ssh-keygen -t rsa
Creamos la llave ssh para el servidor
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
Pasamos el Certificado de Let’s Encrypt
rsync -avi –delete /etc/letsencrypt [email protected]:/etc/
Reiniciamos el servicio
ssh [email protected] /etc/init.d/nginx restart
Todos estos comandos una vez que ya lo hicimos la primera vez lo podemos automatizar en un script para que cuando valla a renovar el certificado lo haga automáticamente:
touch ~/ssl.sh
nano ~/ssl.sh
1 2 3 4 5 6 7 8 9 10 11 | #!/bin/bash # /etc/init.d/nginx stop /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log #/opt/letsencrypt/letsencrypt-auto certonly --standalone -d dominio.cu -d mail.dominio.cu -d smtp.dominio.cu -d pop.dominio.cu -d pop3.dominio.cu -d imap.dominio.cu -d www.dominio.cu -d webmail.dominio.cu -d proxy.dominio.cu -d download.dominio.cu -d openvpn.dominio.cu /etc/init.d/nginx start #Server Web rsync -avi --delete /etc/letsencrypt root@www.dominio.cu:/etc/ ssh root@www.dominio.cu /etc/init.d/nginx restart |
Configuración del Nginx
apt-get install nginx
/etc/nginx/nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | user www-data; worker_processes 2; pid /run/nginx.pid; events { worker_connections 768; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; gzip_http_version 1.1; gzip_vary on; gzip_comp_level 6; gzip_proxied any; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js; gzip_buffers 16 8k; gzip_disable "MSIE [1-6].(?!.*SV1)"; gzip_static on; ignore_invalid_headers on; keepalive_requests 100; keepalive_disable none; max_ranges 1; include /etc/nginx/conf.d/*.conf; include /etc/nginx/ban_tor_net.conf; include /etc/nginx/sites-enabled/*; } |
/etc/nginx/ban_tor_net.conf
Esto es un listado que sacamos de https://www.dan.me.uk/torlist/ para banear en el Nginx las IP Tor aunque se aconseja que se DROP a través de iptables tambien
1 2 3 4 5 6 7 8 9 10 11 12 13 | deny 100.0.240.30; deny 100.11.109.99; deny 100.34.15.226; deny 100.36.111.217; deny 100.36.136.10; deny 100.38.159.190; deny 101.100.140.94; deny 101.100.144.174; deny 101.164.68.36; deny 101.167.33.247; deny 101.55.125.10; deny 101.98.11.146; deny 103.10.197.50; |
Bueno ahora pasamos a configurar los Virtual Hosts, en este primer momento lo hace como Proxy Inverso, pero primero crearemos archivos y configuraciones que usaremos en todos nuestros sitios:
Baneamos todas las expresiones de Exploits en Nginx
nano /etc/nginx/ban_exploits.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | ## Block SQL injections set $block_sql_injections 0; if ($query_string ~ "union.*select.*\(") { set $block_sql_injections 1; } if ($query_string ~ "union.*all.*select.*") { set $block_sql_injections 1; } if ($query_string ~ "concat.*\(") { set $block_sql_injections 1; } if ($block_sql_injections = 1) { return 403; } ## Block file injections set $block_file_injections 0; if ($query_string ~ "[a-zA-Z0-9_]=http://") { set $block_file_injections 1; } if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") { set $block_file_injections 1; } if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") { set $block_file_injections 1; } if ($block_file_injections = 1) { return 403; } ## Block common exploits set $block_common_exploits 0; if ($query_string ~ "(|%3E)") { set $block_common_exploits 1; } if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { set $block_common_exploits 1; } if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { set $block_common_exploits 1; } if ($query_string ~ "proc/self/environ") { set $block_common_exploits 1; } if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") { set $block_common_exploits 1; } if ($query_string ~ "base64_(en|de)code\(.*\)") { set $block_common_exploits 1; } if ($block_common_exploits = 1) { return 403; } ## Block spam set $block_spam 0; if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b") { set $block_spam 1; } if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b") { set $block_spam 1; } if ($query_string ~ "\b(ambien|blue\spill|cialis|cocaine|ejaculation|erectile)\b") { set $block_spam 1; } if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b") { set $block_spam 1; } if ($block_spam = 1) { return 403; } ## Block user agents set $block_user_agents 0; # Don't disable wget if you need it to run cron jobs! #if ($http_user_agent ~ "Wget") { # set $block_user_agents 1; #} # Disable Akeeba Remote Control 2.5 and earlier if ($http_user_agent ~ "Indy Library") { set $block_user_agents 1; } # Common bandwidth hoggers and hacking tools. if ($http_user_agent ~ "libwww-perl") { set $block_user_agents 1; } if ($http_user_agent ~ "GetRight") { set $block_user_agents 1; } if ($http_user_agent ~ "GetWeb!") { set $block_user_agents 1; } if ($http_user_agent ~ "Go!Zilla") { set $block_user_agents 1; } if ($http_user_agent ~ "Download Demon") { set $block_user_agents 1; } if ($http_user_agent ~ "Go-Ahead-Got-It") { set $block_user_agents 1; } if ($http_user_agent ~ "TurnitinBot") { set $block_user_agents 1; } if ($http_user_agent ~ "GrabNet") { set $block_user_agents 1; } if ($block_user_agents = 1) { return 403; } |
Creamos el favicon que sera para todas nuestras webs en caso que no la tenga y lo ponemos en /var/www
nano /etc/nginx/favicon.conf
1 2 3 4 5 | location ~ /favicon.ico { access_log off; log_not_found off; alias /var/www/favicon.ico; } |
Personalizamos las pagina de error del nginx
nano /etc/nginx/error.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } error_page 502 /50x.html; location = /50x.html { root /var/www/; } error_page 403 /403.html; location = /403.html { root /var/www; } |
Creamos la configuración para todos los Dominios que tendran let’s encrypt
Generate Strong Diffie-Hellman Group
1 | sudo openssl dhparam -out /etc/ssl/certs/dominio.pem 2048 |
nano /etc/nginx/ssl.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | resolver 8.8.8.8 valid=300s; resolver_timeout 5s; ssl_certificate /etc/letsencrypt/live/dominio.cu/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/dominio.cu/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/dominio.cu/chain.pem; ssl on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dominio.pem; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; ssl_session_timeout 1440m; ssl_session_cache builtin:1000 shared:SSL:10m; spdy_headers_comp 0; add_header Strict-Transport-Security "max-age=15768000;"; add_header X-Xss-Protection "1; mode=block"; add_header X-Frame-Options "SAMEORIGIN"; # add_header X-Content-Type-Options "nosniff"; # add_header X-Permitted-Cross-Domain-Policies "master-only"; add_header Cache-Control "public"; add_header Public-Key-Pins 'pin-sha256="94h51gJiEKZVEwaG4r2YHLAOQGepNRzE/PYytHrBr/A="; pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; max-age=2592000'; location ~ /.well-known { allow all; } |
Eliminamos el VirtualHost por defecto del Nginx
rm /etc/nginx/sites-enabled/default
Ahora para una mejor gestion sugiero crear una conf por cada host virtual que vallas a usar
nano /etc/nginx/sites-enabled/maildominio
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | server { listen 80; server_name mail.dominio.cu; return 301 https://$host$request_uri; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; include /etc/nginx/error.conf; } server { listen 443 ssl; server_name mail.dominio.cu; include /etc/nginx/ssl.conf; include /etc/nginx/error.conf; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; access_log /var/log/nginx/mail-access.log; error_log /var/log/nginx/mail-error.log; location / { proxy_set_header Host $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; proxy_pass https://192.168.0.2; proxy_read_timeout 90; proxy_redirect https://192.168.0.2 https://mail.dominio.cu; } location ~ /(\.|wp-config.php|readme.html|license.txt|schema.txt|password.txt|passwords.txt|phpmyadmin|admin|download|iredadmin|traza|colas) { deny all; } } |
En el caso que quieras habilitar el sitio por http y https seria de la siguiente forma
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | server { listen 80; server_name mail.dominio.cu; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; include /etc/nginx/error.conf; location / { proxy_set_header Host $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; proxy_pass https://192.168.0.2; proxy_read_timeout 90; proxy_redirect https://192.168.0.2 https://mail.dominio.cu; } } server { listen 443 ssl; server_name mail.dominio.cu; include /etc/nginx/ssl.conf; include /etc/nginx/error.conf; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; access_log /var/log/nginx/mail-access.log; error_log /var/log/nginx/mail-error.log; location / { proxy_set_header Host $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; proxy_pass https://192.168.0.2; proxy_read_timeout 90; proxy_redirect https://192.168.0.2 https://mail.dominio.cu; } location ~ /(\.|wp-config.php|readme.html|license.txt|schema.txt|password.txt|passwords.txt|phpmyadmin|admin|download|iredadmin|traza|colas) { deny all; } } |
Ya de esta forma debe funcionarte perfectamente el Nginx Proxy Inverso
Configurando el Nginx Web Server
En /etc/nginx/nginx.conf ponemos la misma conf del nginx proxy inverso acá las cosas donde van a variar es en los virtualhost y a la hora de darle soporte al php.
apt-get install nginx php5-fpm mysql-server-5.6 phpmyadmin
nano /etc/nginx/php.conf
1 2 3 4 5 | location ~ \.php$ { try_files $uri /index.php; include fastcgi_params; fastcgi_pass unix:/var/run/php5-fpm.sock; } |
Creamos la plantila para el phpmyadmin
ln -s /usr/share/phpmyadmin/ /var/www/phpmyadmin
mkdir -p /etc/nginx/templates/
nano /etc/nginx/templates/phpmyadmin.tmpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | set $pma_doc_root /var/www; set $pma_socket unix:/var/run/php5-fpm.sock; location /phpmyadmin { root $pma_doc_root; index index.php index.html index.htm; location ~ ^/phpmyadmin/(.+\.php)$ { try_files $uri =404; root $pma_doc_root; fastcgi_pass $pma_socket; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $request_filename; include /etc/nginx/fastcgi_params; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_buffer_size 128k; fastcgi_buffers 256 4k; fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_intercept_errors on; } location ~* ^/phpmyadmin/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ { root $pma_doc_root; } } location /phpMyAdmin { rewrite ^/* /phpmyadmin last; } |
Si deseamos darle soporte a un sitio para acceder al phpmyadmin solamente tenemos que poner en http o https del virtualhost lo siguiente
include /etc/nginx/templates/phpmyadmin.tmpl;
Creamos el virtual host para www.dominio.cu con soporte para PHP
mkdir -p /var/www/www.dominio.cu/html
nano /etc/nginx/sites-enabled/www
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | server { listen 80; server_name www.dominio.cu; return 301 https://$host$request_uri; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; } server { listen 443 ssl; server_name www.dominio.cu; include /etc/nginx/ssl.conf; include /etc/nginx/php.conf; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; index index.php index.html index.htm; root /var/www/www.dominio.cu/html; index index.php index.html index.htm; location / { try_files $uri $uri/ /index.php?$args ; } access_log /var/log/nginx/www.dominio.cu-access.log; error_log /var/log/nginx/www.dominio.cu-error.log; } |
Creamos el virtual host para download.dominio.cu con soporte para Indexar
nano /etc/nginx/sites-enabled/download
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | server { listen 80; server_name download.dominio.cu; return 301 https://$host$request_uri; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; } server { listen 443 ssl; server_name download.dominio.cu; include /etc/nginx/ssl.conf; include /etc/nginx/ban_exploits.conf; include /etc/nginx/favicon.conf; autoindex on; root /var/www/download.dominio.cu/html; location / { } access_log /var/log/nginx/download.dominio.cu-access.log; error_log /var/log/nginx/download.dominio.cu-error.log; } |
Bueno ya con esto tienes un servidor en Nginx con Let’s Encrypt con todo lo que se debe, cualquier duda o algo me pueden escribir a armandof (at) armandof.com
Una duda, teniendo internet(usando proxies) y un dominio de 3 o 4 nivel se podria usar para desplegarlo en una lan? o es obligado para poder usarlo tener IPs de cara a internet?
Saludos
Obligado es necesario tener un dominio de cara a internet con IP publicas
tienes que especifical que es para ubuntu este tuto jejeje
funciona en debian 8, también