[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-/blog/tutorial/nginx-reverse-proxy-ssl":3,"prev-/blog/tutorial/nginx-reverse-proxy-ssl":1670,"next-/blog/tutorial/nginx-reverse-proxy-ssl":1673,"related-/blog/tutorial/nginx-reverse-proxy-ssl":1676},{"id":4,"title":5,"author":6,"authorUrl":7,"body":8,"category":1638,"cta":1639,"date":1641,"dateModified":1641,"description":1642,"draft":1643,"extension":1644,"faq":1645,"featured":1643,"image":1658,"imageAlt":1659,"meta":1660,"navigation":231,"path":1661,"readingTime":253,"seo":1662,"stem":1663,"tags":1664,"__hash__":1669},"blog/blog/tutorial/nginx-reverse-proxy-ssl.md","Configurar Nginx como reverse proxy con SSL gratuito","Syswork México","/nosotros",{"type":9,"value":10,"toc":1622},"minimark",[11,26,29,34,42,105,109,157,164,168,179,182,356,359,399,419,426,429,433,442,463,466,486,489,506,513,518,521,629,633,636,680,683,687,690,945,948,1026,1028,1032,1043,1213,1217,1220,1269,1278,1282,1290,1405,1408,1410,1414,1417,1456,1460,1463,1553,1557,1560,1609,1618],[12,13,14,15,20,21,25],"p",{},"Tus aplicaciones no deberían estar expuestas directamente a internet. Un servidor ",[16,17,19],"a",{"href":18},"/tecnologias/nodejs","Node.js"," escuchando en el puerto 3000, un ",[16,22,24],{"href":23},"/soluciones/erp","ERP"," en el 8069, una API en el 8080 — cada uno con su puerto abierto al mundo, sin SSL, sin protección. Nginx como reverse proxy resuelve todo eso: un solo punto de entrada con HTTPS, certificados gratuitos que se renuevan solos y la capacidad de manejar múltiples aplicaciones bajo diferentes dominios o rutas.",[12,27,28],{},"En esta guía vas a configurar Nginx como reverse proxy con SSL de Let's Encrypt para exponer una o varias aplicaciones web de forma segura.",[30,31,33],"h2",{"id":32},"requisitos-previos","Requisitos previos",[12,35,36,37,41],{},"Un servidor Ubuntu 24.04 con IP pública, un dominio que apunte a esa IP (registro DNS tipo A) y tus aplicaciones corriendo en puertos internos. Tu ",[16,38,40],{"href":39},"/blog/configurar-firewall-ufw-linux","firewall UFW"," debe permitir los puertos 80 y 443.",[43,44,49],"pre",{"className":45,"code":46,"language":47,"meta":48,"style":48},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","sudo ufw allow 80/tcp comment 'HTTP'\nsudo ufw allow 443/tcp comment 'HTTPS'\n","bash","",[50,51,52,84],"code",{"__ignoreMap":48},[53,54,57,61,65,68,71,74,78,81],"span",{"class":55,"line":56},"line",1,[53,58,60],{"class":59},"sbgvK","sudo",[53,62,64],{"class":63},"s_sjI"," ufw",[53,66,67],{"class":63}," allow",[53,69,70],{"class":63}," 80/tcp",[53,72,73],{"class":63}," comment",[53,75,77],{"class":76},"sjJ54"," '",[53,79,80],{"class":63},"HTTP",[53,82,83],{"class":76},"'\n",[53,85,87,89,91,93,96,98,100,103],{"class":55,"line":86},2,[53,88,60],{"class":59},[53,90,64],{"class":63},[53,92,67],{"class":63},[53,94,95],{"class":63}," 443/tcp",[53,97,73],{"class":63},[53,99,77],{"class":76},[53,101,102],{"class":63},"HTTPS",[53,104,83],{"class":76},[30,106,108],{"id":107},"paso-1-instalar-nginx","Paso 1: Instalar Nginx",[43,110,112],{"className":45,"code":111,"language":47,"meta":48,"style":48},"sudo apt update\nsudo apt install nginx -y\nsudo systemctl enable --now nginx\n",[50,113,114,124,140],{"__ignoreMap":48},[53,115,116,118,121],{"class":55,"line":56},[53,117,60],{"class":59},[53,119,120],{"class":63}," apt",[53,122,123],{"class":63}," update\n",[53,125,126,128,130,133,136],{"class":55,"line":86},[53,127,60],{"class":59},[53,129,120],{"class":63},[53,131,132],{"class":63}," install",[53,134,135],{"class":63}," nginx",[53,137,139],{"class":138},"stzsN"," -y\n",[53,141,143,145,148,151,154],{"class":55,"line":142},3,[53,144,60],{"class":59},[53,146,147],{"class":63}," systemctl",[53,149,150],{"class":63}," enable",[53,152,153],{"class":138}," --now",[53,155,156],{"class":63}," nginx\n",[12,158,159,160,163],{},"Verifica accediendo a ",[50,161,162],{},"http://tu-ip-publica"," — deberías ver la página por defecto de Nginx.",[30,165,167],{"id":166},"paso-2-configurar-el-reverse-proxy","Paso 2: Configurar el reverse proxy",[12,169,170,171,174,175,178],{},"Supongamos que tienes una aplicación corriendo en ",[50,172,173],{},"localhost:3000"," y quieres exponerla en ",[50,176,177],{},"app.tuempresa.com"," con HTTPS.",[12,180,181],{},"Crea el archivo de configuración del sitio:",[43,183,185],{"className":45,"code":184,"language":47,"meta":48,"style":48},"sudo tee /etc/nginx/sites-available/app.tuempresa.com > /dev/null \u003C\u003C'EOF'\nserver {\n    listen 80;\n    server_name app.tuempresa.com;\n\n    location / {\n        proxy_pass http://localhost:3000;\n        proxy_http_version 1.1;\n\n        # Headers esenciales para que la app sepa quién es el cliente real\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # WebSocket support (necesario para apps en tiempo real)\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n\n        # Timeouts para aplicaciones que procesan peticiones largas\n        proxy_connect_timeout 60s;\n        proxy_send_timeout 60s;\n        proxy_read_timeout 60s;\n    }\n}\nEOF\n",[50,186,187,210,215,220,226,233,239,245,251,256,262,268,274,280,286,291,297,303,309,314,320,326,332,338,344,350],{"__ignoreMap":48},[53,188,189,191,194,197,201,204,207],{"class":55,"line":56},[53,190,60],{"class":59},[53,192,193],{"class":63}," tee",[53,195,196],{"class":63}," /etc/nginx/sites-available/app.tuempresa.com",[53,198,200],{"class":199},"smGrS"," >",[53,202,203],{"class":63}," /dev/null",[53,205,206],{"class":199}," \u003C\u003C",[53,208,209],{"class":76},"'EOF'\n",[53,211,212],{"class":55,"line":86},[53,213,214],{"class":63},"server {\n",[53,216,217],{"class":55,"line":142},[53,218,219],{"class":63},"    listen 80;\n",[53,221,223],{"class":55,"line":222},4,[53,224,225],{"class":63},"    server_name app.tuempresa.com;\n",[53,227,229],{"class":55,"line":228},5,[53,230,232],{"emptyLinePlaceholder":231},true,"\n",[53,234,236],{"class":55,"line":235},6,[53,237,238],{"class":63},"    location / {\n",[53,240,242],{"class":55,"line":241},7,[53,243,244],{"class":63},"        proxy_pass http://localhost:3000;\n",[53,246,248],{"class":55,"line":247},8,[53,249,250],{"class":63},"        proxy_http_version 1.1;\n",[53,252,254],{"class":55,"line":253},9,[53,255,232],{"emptyLinePlaceholder":231},[53,257,259],{"class":55,"line":258},10,[53,260,261],{"class":63},"        # Headers esenciales para que la app sepa quién es el cliente real\n",[53,263,265],{"class":55,"line":264},11,[53,266,267],{"class":63},"        proxy_set_header Host $host;\n",[53,269,271],{"class":55,"line":270},12,[53,272,273],{"class":63},"        proxy_set_header X-Real-IP $remote_addr;\n",[53,275,277],{"class":55,"line":276},13,[53,278,279],{"class":63},"        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",[53,281,283],{"class":55,"line":282},14,[53,284,285],{"class":63},"        proxy_set_header X-Forwarded-Proto $scheme;\n",[53,287,289],{"class":55,"line":288},15,[53,290,232],{"emptyLinePlaceholder":231},[53,292,294],{"class":55,"line":293},16,[53,295,296],{"class":63},"        # WebSocket support (necesario para apps en tiempo real)\n",[53,298,300],{"class":55,"line":299},17,[53,301,302],{"class":63},"        proxy_set_header Upgrade $http_upgrade;\n",[53,304,306],{"class":55,"line":305},18,[53,307,308],{"class":63},"        proxy_set_header Connection \"upgrade\";\n",[53,310,312],{"class":55,"line":311},19,[53,313,232],{"emptyLinePlaceholder":231},[53,315,317],{"class":55,"line":316},20,[53,318,319],{"class":63},"        # Timeouts para aplicaciones que procesan peticiones largas\n",[53,321,323],{"class":55,"line":322},21,[53,324,325],{"class":63},"        proxy_connect_timeout 60s;\n",[53,327,329],{"class":55,"line":328},22,[53,330,331],{"class":63},"        proxy_send_timeout 60s;\n",[53,333,335],{"class":55,"line":334},23,[53,336,337],{"class":63},"        proxy_read_timeout 60s;\n",[53,339,341],{"class":55,"line":340},24,[53,342,343],{"class":63},"    }\n",[53,345,347],{"class":55,"line":346},25,[53,348,349],{"class":63},"}\n",[53,351,353],{"class":55,"line":352},26,[53,354,355],{"class":76},"EOF\n",[12,357,358],{},"Habilita el sitio y verifica la configuración:",[43,360,362],{"className":45,"code":361,"language":47,"meta":48,"style":48},"sudo ln -s /etc/nginx/sites-available/app.tuempresa.com /etc/nginx/sites-enabled/\nsudo nginx -t\nsudo systemctl reload nginx\n",[50,363,364,379,388],{"__ignoreMap":48},[53,365,366,368,371,374,376],{"class":55,"line":56},[53,367,60],{"class":59},[53,369,370],{"class":63}," ln",[53,372,373],{"class":138}," -s",[53,375,196],{"class":63},[53,377,378],{"class":63}," /etc/nginx/sites-enabled/\n",[53,380,381,383,385],{"class":55,"line":86},[53,382,60],{"class":59},[53,384,135],{"class":63},[53,386,387],{"class":138}," -t\n",[53,389,390,392,394,397],{"class":55,"line":142},[53,391,60],{"class":59},[53,393,147],{"class":63},[53,395,396],{"class":63}," reload",[53,398,156],{"class":63},[400,401,404],"alert",{"title":402,"type":403},"¿Por qué proxy_set_header?","info",[12,405,406,407,410,411,414,415,418],{},"Sin estos headers, tu aplicación ve todas las peticiones como si vinieran de ",[50,408,409],{},"127.0.0.1"," (Nginx). Con ",[50,412,413],{},"X-Real-IP"," y ",[50,416,417],{},"X-Forwarded-For",", la aplicación conoce la IP real del cliente — esencial para logs, rate limiting y geolocalización.",[12,420,421,422,425],{},"En este punto, ",[50,423,424],{},"http://app.tuempresa.com"," ya muestra tu aplicación. Pero sin SSL — vamos a arreglar eso.",[427,428],"ad-banner",{},[30,430,432],{"id":431},"paso-3-instalar-certbot-y-obtener-certificado-ssl","Paso 3: Instalar Certbot y obtener certificado SSL",[12,434,435,441],{},[16,436,440],{"href":437,"rel":438},"https://certbot.eff.org/",[439],"nofollow","Certbot"," es la herramienta oficial de Let's Encrypt para obtener y renovar certificados SSL automáticamente:",[43,443,445],{"className":45,"code":444,"language":47,"meta":48,"style":48},"sudo apt install certbot python3-certbot-nginx -y\n",[50,446,447],{"__ignoreMap":48},[53,448,449,451,453,455,458,461],{"class":55,"line":56},[53,450,60],{"class":59},[53,452,120],{"class":63},[53,454,132],{"class":63},[53,456,457],{"class":63}," certbot",[53,459,460],{"class":63}," python3-certbot-nginx",[53,462,139],{"class":138},[12,464,465],{},"Obtén el certificado — Certbot configura Nginx automáticamente:",[43,467,469],{"className":45,"code":468,"language":47,"meta":48,"style":48},"sudo certbot --nginx -d app.tuempresa.com\n",[50,470,471],{"__ignoreMap":48},[53,472,473,475,477,480,483],{"class":55,"line":56},[53,474,60],{"class":59},[53,476,457],{"class":63},[53,478,479],{"class":138}," --nginx",[53,481,482],{"class":138}," -d",[53,484,485],{"class":63}," app.tuempresa.com\n",[12,487,488],{},"Certbot te pide:",[490,491,492,496,499],"ol",{},[493,494,495],"li",{},"Email para notificaciones de renovación",[493,497,498],{},"Aceptar los términos de servicio",[493,500,501,502],{},"Si quieres redirigir HTTP a HTTPS automáticamente — ",[503,504,505],"strong",{},"di que sí",[12,507,508,509,512],{},"En 30 segundos tienes HTTPS funcionando. Verifica en ",[50,510,511],{},"https://app.tuempresa.com",".",[514,515,517],"h3",{"id":516},"qué-hizo-certbot","¿Qué hizo Certbot?",[12,519,520],{},"Certbot modificó tu archivo de configuración de Nginx agregando las directivas de SSL y una redirección automática de HTTP a HTTPS. Si abres el archivo verás algo como:",[43,522,526],{"className":523,"code":524,"language":525,"meta":48,"style":48},"language-nginx shiki shiki-themes material-theme-lighter github-light github-dark","server {\n    server_name app.tuempresa.com;\n\n    location / {\n        proxy_pass http://localhost:3000;\n        # ... (tus headers originales)\n    }\n\n    listen 443 ssl;\n    ssl_certificate /etc/letsencrypt/live/app.tuempresa.com/fullchain.pem;\n    ssl_certificate_key /etc/letsencrypt/live/app.tuempresa.com/privkey.pem;\n    include /etc/letsencrypt/options-ssl-nginx.conf;\n    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;\n}\n\nserver {\n    if ($host = app.tuempresa.com) {\n        return 301 https://$host$request_uri;\n    }\n    listen 80;\n    server_name app.tuempresa.com;\n    return 404;\n}\n","nginx",[50,527,528,532,536,540,544,548,553,557,561,566,571,576,581,586,590,594,598,603,608,612,616,620,625],{"__ignoreMap":48},[53,529,530],{"class":55,"line":56},[53,531,214],{},[53,533,534],{"class":55,"line":86},[53,535,225],{},[53,537,538],{"class":55,"line":142},[53,539,232],{"emptyLinePlaceholder":231},[53,541,542],{"class":55,"line":222},[53,543,238],{},[53,545,546],{"class":55,"line":228},[53,547,244],{},[53,549,550],{"class":55,"line":235},[53,551,552],{},"        # ... (tus headers originales)\n",[53,554,555],{"class":55,"line":241},[53,556,343],{},[53,558,559],{"class":55,"line":247},[53,560,232],{"emptyLinePlaceholder":231},[53,562,563],{"class":55,"line":253},[53,564,565],{},"    listen 443 ssl;\n",[53,567,568],{"class":55,"line":258},[53,569,570],{},"    ssl_certificate /etc/letsencrypt/live/app.tuempresa.com/fullchain.pem;\n",[53,572,573],{"class":55,"line":264},[53,574,575],{},"    ssl_certificate_key /etc/letsencrypt/live/app.tuempresa.com/privkey.pem;\n",[53,577,578],{"class":55,"line":270},[53,579,580],{},"    include /etc/letsencrypt/options-ssl-nginx.conf;\n",[53,582,583],{"class":55,"line":276},[53,584,585],{},"    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;\n",[53,587,588],{"class":55,"line":282},[53,589,349],{},[53,591,592],{"class":55,"line":288},[53,593,232],{"emptyLinePlaceholder":231},[53,595,596],{"class":55,"line":293},[53,597,214],{},[53,599,600],{"class":55,"line":299},[53,601,602],{},"    if ($host = app.tuempresa.com) {\n",[53,604,605],{"class":55,"line":305},[53,606,607],{},"        return 301 https://$host$request_uri;\n",[53,609,610],{"class":55,"line":311},[53,611,343],{},[53,613,614],{"class":55,"line":316},[53,615,219],{},[53,617,618],{"class":55,"line":322},[53,619,225],{},[53,621,622],{"class":55,"line":328},[53,623,624],{},"    return 404;\n",[53,626,627],{"class":55,"line":334},[53,628,349],{},[514,630,632],{"id":631},"renovación-automática","Renovación automática",[12,634,635],{},"Certbot instala un timer de systemd que verifica los certificados dos veces al día y los renueva automáticamente antes de que expiren (cada 90 días):",[43,637,639],{"className":45,"code":638,"language":47,"meta":48,"style":48},"# Verificar que el timer está activo\nsudo systemctl status certbot.timer\n\n# Probar renovación en seco\nsudo certbot renew --dry-run\n",[50,640,641,647,659,663,668],{"__ignoreMap":48},[53,642,643],{"class":55,"line":56},[53,644,646],{"class":645},"sutJx","# Verificar que el timer está activo\n",[53,648,649,651,653,656],{"class":55,"line":86},[53,650,60],{"class":59},[53,652,147],{"class":63},[53,654,655],{"class":63}," status",[53,657,658],{"class":63}," certbot.timer\n",[53,660,661],{"class":55,"line":142},[53,662,232],{"emptyLinePlaceholder":231},[53,664,665],{"class":55,"line":222},[53,666,667],{"class":645},"# Probar renovación en seco\n",[53,669,670,672,674,677],{"class":55,"line":228},[53,671,60],{"class":59},[53,673,457],{"class":63},[53,675,676],{"class":63}," renew",[53,678,679],{"class":138}," --dry-run\n",[12,681,682],{},"Si la prueba pasa, no tienes que hacer nada más — el certificado se renueva solo para siempre.",[30,684,686],{"id":685},"paso-4-múltiples-aplicaciones-en-el-mismo-servidor","Paso 4: Múltiples aplicaciones en el mismo servidor",[12,688,689],{},"La verdadera potencia del reverse proxy aparece cuando tienes varias aplicaciones en el mismo servidor, cada una con su dominio y SSL:",[43,691,693],{"className":45,"code":692,"language":47,"meta":48,"style":48},"# ERP en erp.tuempresa.com → localhost:8069\nsudo tee /etc/nginx/sites-available/erp.tuempresa.com > /dev/null \u003C\u003C'EOF'\nserver {\n    listen 80;\n    server_name erp.tuempresa.com;\n\n    client_max_body_size 100M;  # ERP sube archivos grandes\n\n    location / {\n        proxy_pass http://localhost:8069;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    # Longpolling (necesario para Odoo/ERP)\n    location /longpolling {\n        proxy_pass http://localhost:8072;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    }\n}\nEOF\n\n# Grafana en monitor.tuempresa.com → localhost:3000\nsudo tee /etc/nginx/sites-available/monitor.tuempresa.com > /dev/null \u003C\u003C'EOF'\nserver {\n    listen 80;\n    server_name monitor.tuempresa.com;\n\n    location / {\n        proxy_pass http://localhost:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    location /api/live/ws {\n        proxy_pass http://localhost:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n    }\n}\nEOF\n",[50,694,695,700,717,721,725,730,734,739,743,747,752,756,760,764,768,772,776,781,786,791,795,799,803,807,811,815,819,825,843,848,853,859,864,869,874,879,884,889,894,899,904,910,915,920,925,930,935,940],{"__ignoreMap":48},[53,696,697],{"class":55,"line":56},[53,698,699],{"class":645},"# ERP en erp.tuempresa.com → localhost:8069\n",[53,701,702,704,706,709,711,713,715],{"class":55,"line":86},[53,703,60],{"class":59},[53,705,193],{"class":63},[53,707,708],{"class":63}," /etc/nginx/sites-available/erp.tuempresa.com",[53,710,200],{"class":199},[53,712,203],{"class":63},[53,714,206],{"class":199},[53,716,209],{"class":76},[53,718,719],{"class":55,"line":142},[53,720,214],{"class":63},[53,722,723],{"class":55,"line":222},[53,724,219],{"class":63},[53,726,727],{"class":55,"line":228},[53,728,729],{"class":63},"    server_name erp.tuempresa.com;\n",[53,731,732],{"class":55,"line":235},[53,733,232],{"emptyLinePlaceholder":231},[53,735,736],{"class":55,"line":241},[53,737,738],{"class":63},"    client_max_body_size 100M;  # ERP sube archivos grandes\n",[53,740,741],{"class":55,"line":247},[53,742,232],{"emptyLinePlaceholder":231},[53,744,745],{"class":55,"line":253},[53,746,238],{"class":63},[53,748,749],{"class":55,"line":258},[53,750,751],{"class":63},"        proxy_pass http://localhost:8069;\n",[53,753,754],{"class":55,"line":264},[53,755,267],{"class":63},[53,757,758],{"class":55,"line":270},[53,759,273],{"class":63},[53,761,762],{"class":55,"line":276},[53,763,279],{"class":63},[53,765,766],{"class":55,"line":282},[53,767,285],{"class":63},[53,769,770],{"class":55,"line":288},[53,771,343],{"class":63},[53,773,774],{"class":55,"line":293},[53,775,232],{"emptyLinePlaceholder":231},[53,777,778],{"class":55,"line":299},[53,779,780],{"class":63},"    # Longpolling (necesario para Odoo/ERP)\n",[53,782,783],{"class":55,"line":305},[53,784,785],{"class":63},"    location /longpolling {\n",[53,787,788],{"class":55,"line":311},[53,789,790],{"class":63},"        proxy_pass http://localhost:8072;\n",[53,792,793],{"class":55,"line":316},[53,794,267],{"class":63},[53,796,797],{"class":55,"line":322},[53,798,273],{"class":63},[53,800,801],{"class":55,"line":328},[53,802,279],{"class":63},[53,804,805],{"class":55,"line":334},[53,806,343],{"class":63},[53,808,809],{"class":55,"line":340},[53,810,349],{"class":63},[53,812,813],{"class":55,"line":346},[53,814,355],{"class":76},[53,816,817],{"class":55,"line":352},[53,818,232],{"emptyLinePlaceholder":231},[53,820,822],{"class":55,"line":821},27,[53,823,824],{"class":645},"# Grafana en monitor.tuempresa.com → localhost:3000\n",[53,826,828,830,832,835,837,839,841],{"class":55,"line":827},28,[53,829,60],{"class":59},[53,831,193],{"class":63},[53,833,834],{"class":63}," /etc/nginx/sites-available/monitor.tuempresa.com",[53,836,200],{"class":199},[53,838,203],{"class":63},[53,840,206],{"class":199},[53,842,209],{"class":76},[53,844,846],{"class":55,"line":845},29,[53,847,214],{"class":63},[53,849,851],{"class":55,"line":850},30,[53,852,219],{"class":63},[53,854,856],{"class":55,"line":855},31,[53,857,858],{"class":63},"    server_name monitor.tuempresa.com;\n",[53,860,862],{"class":55,"line":861},32,[53,863,232],{"emptyLinePlaceholder":231},[53,865,867],{"class":55,"line":866},33,[53,868,238],{"class":63},[53,870,872],{"class":55,"line":871},34,[53,873,244],{"class":63},[53,875,877],{"class":55,"line":876},35,[53,878,267],{"class":63},[53,880,882],{"class":55,"line":881},36,[53,883,273],{"class":63},[53,885,887],{"class":55,"line":886},37,[53,888,279],{"class":63},[53,890,892],{"class":55,"line":891},38,[53,893,285],{"class":63},[53,895,897],{"class":55,"line":896},39,[53,898,343],{"class":63},[53,900,902],{"class":55,"line":901},40,[53,903,232],{"emptyLinePlaceholder":231},[53,905,907],{"class":55,"line":906},41,[53,908,909],{"class":63},"    location /api/live/ws {\n",[53,911,913],{"class":55,"line":912},42,[53,914,244],{"class":63},[53,916,918],{"class":55,"line":917},43,[53,919,250],{"class":63},[53,921,923],{"class":55,"line":922},44,[53,924,302],{"class":63},[53,926,928],{"class":55,"line":927},45,[53,929,308],{"class":63},[53,931,933],{"class":55,"line":932},46,[53,934,343],{"class":63},[53,936,938],{"class":55,"line":937},47,[53,939,349],{"class":63},[53,941,943],{"class":55,"line":942},48,[53,944,355],{"class":76},[12,946,947],{},"Habilita los sitios y obtén certificados para todos de una vez:",[43,949,951],{"className":45,"code":950,"language":47,"meta":48,"style":48},"sudo ln -s /etc/nginx/sites-available/erp.tuempresa.com /etc/nginx/sites-enabled/\nsudo ln -s /etc/nginx/sites-available/monitor.tuempresa.com /etc/nginx/sites-enabled/\nsudo nginx -t && sudo systemctl reload nginx\n\n# Certificados para todos los dominios\nsudo certbot --nginx -d erp.tuempresa.com -d monitor.tuempresa.com\n",[50,952,953,965,977,999,1003,1008],{"__ignoreMap":48},[53,954,955,957,959,961,963],{"class":55,"line":56},[53,956,60],{"class":59},[53,958,370],{"class":63},[53,960,373],{"class":138},[53,962,708],{"class":63},[53,964,378],{"class":63},[53,966,967,969,971,973,975],{"class":55,"line":86},[53,968,60],{"class":59},[53,970,370],{"class":63},[53,972,373],{"class":138},[53,974,834],{"class":63},[53,976,378],{"class":63},[53,978,979,981,983,986,990,993,995,997],{"class":55,"line":142},[53,980,60],{"class":59},[53,982,135],{"class":63},[53,984,985],{"class":138}," -t",[53,987,989],{"class":988},"sP7_E"," &&",[53,991,992],{"class":59}," sudo",[53,994,147],{"class":63},[53,996,396],{"class":63},[53,998,156],{"class":63},[53,1000,1001],{"class":55,"line":222},[53,1002,232],{"emptyLinePlaceholder":231},[53,1004,1005],{"class":55,"line":228},[53,1006,1007],{"class":645},"# Certificados para todos los dominios\n",[53,1009,1010,1012,1014,1016,1018,1021,1023],{"class":55,"line":235},[53,1011,60],{"class":59},[53,1013,457],{"class":63},[53,1015,479],{"class":138},[53,1017,482],{"class":138},[53,1019,1020],{"class":63}," erp.tuempresa.com",[53,1022,482],{"class":138},[53,1024,1025],{"class":63}," monitor.tuempresa.com\n",[427,1027],{},[30,1029,1031],{"id":1030},"paso-5-optimización-para-producción","Paso 5: Optimización para producción",[12,1033,1034,1035,1038,1039,1042],{},"La configuración por defecto de Nginx es conservadora. Para producción, agrega estas optimizaciones al bloque ",[50,1036,1037],{},"http"," de ",[50,1040,1041],{},"/etc/nginx/nginx.conf",":",[43,1044,1046],{"className":523,"code":1045,"language":525,"meta":48,"style":48},"http {\n    # --- Rendimiento ---\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n    keepalive_timeout 65;\n    types_hash_max_size 2048;\n\n    # --- Compresión Gzip ---\n    gzip on;\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 5;\n    gzip_min_length 256;\n    gzip_types\n        text/plain\n        text/css\n        text/javascript\n        application/json\n        application/javascript\n        application/xml\n        image/svg+xml;\n\n    # --- Seguridad ---\n    server_tokens off;  # No revelar versión de Nginx\n\n    # --- Buffers ---\n    proxy_buffer_size 128k;\n    proxy_buffers 4 256k;\n    proxy_busy_buffers_size 256k;\n\n    # --- Límites ---\n    client_max_body_size 50M;  # Tamaño máximo de upload\n}\n",[50,1047,1048,1053,1058,1063,1068,1073,1078,1083,1087,1092,1097,1102,1107,1112,1117,1122,1127,1132,1137,1142,1147,1152,1157,1161,1166,1171,1175,1180,1185,1190,1195,1199,1204,1209],{"__ignoreMap":48},[53,1049,1050],{"class":55,"line":56},[53,1051,1052],{},"http {\n",[53,1054,1055],{"class":55,"line":86},[53,1056,1057],{},"    # --- Rendimiento ---\n",[53,1059,1060],{"class":55,"line":142},[53,1061,1062],{},"    sendfile on;\n",[53,1064,1065],{"class":55,"line":222},[53,1066,1067],{},"    tcp_nopush on;\n",[53,1069,1070],{"class":55,"line":228},[53,1071,1072],{},"    tcp_nodelay on;\n",[53,1074,1075],{"class":55,"line":235},[53,1076,1077],{},"    keepalive_timeout 65;\n",[53,1079,1080],{"class":55,"line":241},[53,1081,1082],{},"    types_hash_max_size 2048;\n",[53,1084,1085],{"class":55,"line":247},[53,1086,232],{"emptyLinePlaceholder":231},[53,1088,1089],{"class":55,"line":253},[53,1090,1091],{},"    # --- Compresión Gzip ---\n",[53,1093,1094],{"class":55,"line":258},[53,1095,1096],{},"    gzip on;\n",[53,1098,1099],{"class":55,"line":264},[53,1100,1101],{},"    gzip_vary on;\n",[53,1103,1104],{"class":55,"line":270},[53,1105,1106],{},"    gzip_proxied any;\n",[53,1108,1109],{"class":55,"line":276},[53,1110,1111],{},"    gzip_comp_level 5;\n",[53,1113,1114],{"class":55,"line":282},[53,1115,1116],{},"    gzip_min_length 256;\n",[53,1118,1119],{"class":55,"line":288},[53,1120,1121],{},"    gzip_types\n",[53,1123,1124],{"class":55,"line":293},[53,1125,1126],{},"        text/plain\n",[53,1128,1129],{"class":55,"line":299},[53,1130,1131],{},"        text/css\n",[53,1133,1134],{"class":55,"line":305},[53,1135,1136],{},"        text/javascript\n",[53,1138,1139],{"class":55,"line":311},[53,1140,1141],{},"        application/json\n",[53,1143,1144],{"class":55,"line":316},[53,1145,1146],{},"        application/javascript\n",[53,1148,1149],{"class":55,"line":322},[53,1150,1151],{},"        application/xml\n",[53,1153,1154],{"class":55,"line":328},[53,1155,1156],{},"        image/svg+xml;\n",[53,1158,1159],{"class":55,"line":334},[53,1160,232],{"emptyLinePlaceholder":231},[53,1162,1163],{"class":55,"line":340},[53,1164,1165],{},"    # --- Seguridad ---\n",[53,1167,1168],{"class":55,"line":346},[53,1169,1170],{},"    server_tokens off;  # No revelar versión de Nginx\n",[53,1172,1173],{"class":55,"line":352},[53,1174,232],{"emptyLinePlaceholder":231},[53,1176,1177],{"class":55,"line":821},[53,1178,1179],{},"    # --- Buffers ---\n",[53,1181,1182],{"class":55,"line":827},[53,1183,1184],{},"    proxy_buffer_size 128k;\n",[53,1186,1187],{"class":55,"line":845},[53,1188,1189],{},"    proxy_buffers 4 256k;\n",[53,1191,1192],{"class":55,"line":850},[53,1193,1194],{},"    proxy_busy_buffers_size 256k;\n",[53,1196,1197],{"class":55,"line":855},[53,1198,232],{"emptyLinePlaceholder":231},[53,1200,1201],{"class":55,"line":861},[53,1202,1203],{},"    # --- Límites ---\n",[53,1205,1206],{"class":55,"line":866},[53,1207,1208],{},"    client_max_body_size 50M;  # Tamaño máximo de upload\n",[53,1210,1211],{"class":55,"line":871},[53,1212,349],{},[30,1214,1216],{"id":1215},"paso-6-headers-de-seguridad","Paso 6: Headers de seguridad",[12,1218,1219],{},"Agrega headers de seguridad que protegen a los usuarios de ataques comunes. Puedes agregarlos en la configuración global o por sitio:",[43,1221,1223],{"className":523,"code":1222,"language":525,"meta":48,"style":48},"# Dentro del bloque server { } o en un archivo incluido\nadd_header X-Frame-Options \"SAMEORIGIN\" always;\nadd_header X-Content-Type-Options \"nosniff\" always;\nadd_header X-XSS-Protection \"1; mode=block\" always;\nadd_header Referrer-Policy \"strict-origin-when-cross-origin\" always;\nadd_header Permissions-Policy \"camera=(), microphone=(), geolocation=()\" always;\n\n# HSTS — fuerza HTTPS por 1 año (activar solo si estás seguro de usar HTTPS siempre)\nadd_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\" always;\n",[50,1224,1225,1230,1235,1240,1245,1250,1255,1259,1264],{"__ignoreMap":48},[53,1226,1227],{"class":55,"line":56},[53,1228,1229],{},"# Dentro del bloque server { } o en un archivo incluido\n",[53,1231,1232],{"class":55,"line":86},[53,1233,1234],{},"add_header X-Frame-Options \"SAMEORIGIN\" always;\n",[53,1236,1237],{"class":55,"line":142},[53,1238,1239],{},"add_header X-Content-Type-Options \"nosniff\" always;\n",[53,1241,1242],{"class":55,"line":222},[53,1243,1244],{},"add_header X-XSS-Protection \"1; mode=block\" always;\n",[53,1246,1247],{"class":55,"line":228},[53,1248,1249],{},"add_header Referrer-Policy \"strict-origin-when-cross-origin\" always;\n",[53,1251,1252],{"class":55,"line":235},[53,1253,1254],{},"add_header Permissions-Policy \"camera=(), microphone=(), geolocation=()\" always;\n",[53,1256,1257],{"class":55,"line":241},[53,1258,232],{"emptyLinePlaceholder":231},[53,1260,1261],{"class":55,"line":247},[53,1262,1263],{},"# HSTS — fuerza HTTPS por 1 año (activar solo si estás seguro de usar HTTPS siempre)\n",[53,1265,1266],{"class":55,"line":253},[53,1267,1268],{},"add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\" always;\n",[12,1270,1271,1272,1277],{},"Verifica tu configuración de SSL en ",[16,1273,1276],{"href":1274,"rel":1275},"https://www.ssllabs.com/ssltest/",[439],"SSL Labs"," — con Let's Encrypt y estos headers deberías obtener calificación A o A+.",[30,1279,1281],{"id":1280},"paso-7-balanceo-de-carga","Paso 7: Balanceo de carga",[12,1283,1284,1285,1289],{},"Si tu aplicación tiene múltiples réplicas (por ejemplo, con ",[16,1286,1288],{"href":1287},"/blog/docker-compose-guia-completa","Docker Compose","), Nginx puede distribuir el tráfico entre ellas:",[43,1291,1293],{"className":523,"code":1292,"language":525,"meta":48,"style":48},"upstream app_backend {\n    # Round-robin por defecto\n    server localhost:3001;\n    server localhost:3002;\n    server localhost:3003;\n\n    # Alternativas:\n    # least_conn;      # Envía al servidor con menos conexiones activas\n    # ip_hash;         # Mismo cliente siempre al mismo servidor (sticky sessions)\n}\n\nserver {\n    listen 443 ssl;\n    server_name app.tuempresa.com;\n\n    location / {\n        proxy_pass http://app_backend;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    # SSL config...\n}\n",[50,1294,1295,1300,1305,1310,1315,1320,1324,1329,1334,1339,1343,1347,1351,1355,1359,1363,1367,1372,1376,1380,1384,1388,1392,1396,1401],{"__ignoreMap":48},[53,1296,1297],{"class":55,"line":56},[53,1298,1299],{},"upstream app_backend {\n",[53,1301,1302],{"class":55,"line":86},[53,1303,1304],{},"    # Round-robin por defecto\n",[53,1306,1307],{"class":55,"line":142},[53,1308,1309],{},"    server localhost:3001;\n",[53,1311,1312],{"class":55,"line":222},[53,1313,1314],{},"    server localhost:3002;\n",[53,1316,1317],{"class":55,"line":228},[53,1318,1319],{},"    server localhost:3003;\n",[53,1321,1322],{"class":55,"line":235},[53,1323,232],{"emptyLinePlaceholder":231},[53,1325,1326],{"class":55,"line":241},[53,1327,1328],{},"    # Alternativas:\n",[53,1330,1331],{"class":55,"line":247},[53,1332,1333],{},"    # least_conn;      # Envía al servidor con menos conexiones activas\n",[53,1335,1336],{"class":55,"line":253},[53,1337,1338],{},"    # ip_hash;         # Mismo cliente siempre al mismo servidor (sticky sessions)\n",[53,1340,1341],{"class":55,"line":258},[53,1342,349],{},[53,1344,1345],{"class":55,"line":264},[53,1346,232],{"emptyLinePlaceholder":231},[53,1348,1349],{"class":55,"line":270},[53,1350,214],{},[53,1352,1353],{"class":55,"line":276},[53,1354,565],{},[53,1356,1357],{"class":55,"line":282},[53,1358,225],{},[53,1360,1361],{"class":55,"line":288},[53,1362,232],{"emptyLinePlaceholder":231},[53,1364,1365],{"class":55,"line":293},[53,1366,238],{},[53,1368,1369],{"class":55,"line":299},[53,1370,1371],{},"        proxy_pass http://app_backend;\n",[53,1373,1374],{"class":55,"line":305},[53,1375,267],{},[53,1377,1378],{"class":55,"line":311},[53,1379,273],{},[53,1381,1382],{"class":55,"line":316},[53,1383,279],{},[53,1385,1386],{"class":55,"line":322},[53,1387,285],{},[53,1389,1390],{"class":55,"line":328},[53,1391,343],{},[53,1393,1394],{"class":55,"line":334},[53,1395,232],{"emptyLinePlaceholder":231},[53,1397,1398],{"class":55,"line":340},[53,1399,1400],{},"    # SSL config...\n",[53,1402,1403],{"class":55,"line":346},[53,1404,349],{},[12,1406,1407],{},"Si una réplica falla, Nginx la detecta automáticamente y deja de enviarle tráfico hasta que se recupere.",[427,1409],{},[30,1411,1413],{"id":1412},"caché-de-contenido-estático","Caché de contenido estático",[12,1415,1416],{},"Para aplicaciones que sirven archivos estáticos (imágenes, CSS, JS), configura Nginx para cachearlos y servirlos directamente sin pasar por la aplicación:",[43,1418,1420],{"className":523,"code":1419,"language":525,"meta":48,"style":48},"location ~* \\.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {\n    proxy_pass http://localhost:3000;\n    proxy_cache_valid 200 7d;\n    expires 7d;\n    add_header Cache-Control \"public, immutable\";\n    access_log off;\n}\n",[50,1421,1422,1427,1432,1437,1442,1447,1452],{"__ignoreMap":48},[53,1423,1424],{"class":55,"line":56},[53,1425,1426],{},"location ~* \\.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {\n",[53,1428,1429],{"class":55,"line":86},[53,1430,1431],{},"    proxy_pass http://localhost:3000;\n",[53,1433,1434],{"class":55,"line":142},[53,1435,1436],{},"    proxy_cache_valid 200 7d;\n",[53,1438,1439],{"class":55,"line":222},[53,1440,1441],{},"    expires 7d;\n",[53,1443,1444],{"class":55,"line":228},[53,1445,1446],{},"    add_header Cache-Control \"public, immutable\";\n",[53,1448,1449],{"class":55,"line":235},[53,1450,1451],{},"    access_log off;\n",[53,1453,1454],{"class":55,"line":241},[53,1455,349],{},[30,1457,1459],{"id":1458},"debugging-y-logs","Debugging y logs",[12,1461,1462],{},"Cuando algo no funciona, los logs son tu mejor herramienta:",[43,1464,1466],{"className":45,"code":1465,"language":47,"meta":48,"style":48},"# Logs de acceso\nsudo tail -f /var/log/nginx/access.log\n\n# Logs de error\nsudo tail -f /var/log/nginx/error.log\n\n# Logs por sitio (si los configuras)\naccess_log /var/log/nginx/app.tuempresa.com.access.log;\nerror_log /var/log/nginx/app.tuempresa.com.error.log;\n\n# Verificar configuración antes de recargar\nsudo nginx -t\n",[50,1467,1468,1473,1486,1490,1495,1506,1510,1515,1526,1536,1540,1545],{"__ignoreMap":48},[53,1469,1470],{"class":55,"line":56},[53,1471,1472],{"class":645},"# Logs de acceso\n",[53,1474,1475,1477,1480,1483],{"class":55,"line":86},[53,1476,60],{"class":59},[53,1478,1479],{"class":63}," tail",[53,1481,1482],{"class":138}," -f",[53,1484,1485],{"class":63}," /var/log/nginx/access.log\n",[53,1487,1488],{"class":55,"line":142},[53,1489,232],{"emptyLinePlaceholder":231},[53,1491,1492],{"class":55,"line":222},[53,1493,1494],{"class":645},"# Logs de error\n",[53,1496,1497,1499,1501,1503],{"class":55,"line":228},[53,1498,60],{"class":59},[53,1500,1479],{"class":63},[53,1502,1482],{"class":138},[53,1504,1505],{"class":63}," /var/log/nginx/error.log\n",[53,1507,1508],{"class":55,"line":235},[53,1509,232],{"emptyLinePlaceholder":231},[53,1511,1512],{"class":55,"line":241},[53,1513,1514],{"class":645},"# Logs por sitio (si los configuras)\n",[53,1516,1517,1520,1523],{"class":55,"line":247},[53,1518,1519],{"class":59},"access_log",[53,1521,1522],{"class":63}," /var/log/nginx/app.tuempresa.com.access.log",[53,1524,1525],{"class":988},";\n",[53,1527,1528,1531,1534],{"class":55,"line":253},[53,1529,1530],{"class":59},"error_log",[53,1532,1533],{"class":63}," /var/log/nginx/app.tuempresa.com.error.log",[53,1535,1525],{"class":988},[53,1537,1538],{"class":55,"line":258},[53,1539,232],{"emptyLinePlaceholder":231},[53,1541,1542],{"class":55,"line":264},[53,1543,1544],{"class":645},"# Verificar configuración antes de recargar\n",[53,1546,1547,1549,1551],{"class":55,"line":270},[53,1548,60],{"class":59},[53,1550,135],{"class":63},[53,1552,387],{"class":138},[30,1554,1556],{"id":1555},"siguientes-pasos","Siguientes pasos",[12,1558,1559],{},"Con Nginx configurado como reverse proxy con SSL, puedes mejorar la arquitectura:",[1561,1562,1563,1573,1579,1591,1600],"ul",{},[493,1564,1565,1568,1569,1572],{},[503,1566,1567],{},"Rate limiting"," — protege tus APIs de abuso con ",[50,1570,1571],{},"limit_req_zone"," de Nginx",[493,1574,1575,1578],{},[503,1576,1577],{},"WAF (Web Application Firewall)"," — ModSecurity con Nginx para proteger contra inyección SQL, XSS y OWASP Top 10",[493,1580,1581,1587,1588],{},[503,1582,1583],{},[16,1584,1586],{"href":1585},"/blog/monitoreo-grafana-prometheus","Monitoreo"," — exporta métricas de Nginx a Prometheus con ",[50,1589,1590],{},"nginx-prometheus-exporter",[493,1592,1593,1599],{},[503,1594,1595],{},[16,1596,1598],{"href":1597},"/tecnologias/docker","Docker"," — Nginx como contenedor con Traefik o nginx-proxy para descubrimiento automático de servicios",[493,1601,1602,1608],{},[503,1603,1604],{},[16,1605,1607],{"href":1606},"/servicios/ciberseguridad","Ciberseguridad"," profesional — auditoría de tu configuración web y hardening completo",[1610,1611],"call-to-action",{"description":1612,"eyebrow":1613,"icon":1614,"label":1615,"title":1616,"to":1617},"Diseñamos e implementamos Nginx, SSL, balanceo de carga y alta disponibilidad para tus aplicaciones empresariales.","Infraestructura web","i-lucide-globe","Solicitar evaluación","¿Necesitas ayuda con la arquitectura web de tu aplicación?","/contacto",[1619,1620,1621],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":48,"searchDepth":86,"depth":142,"links":1623},[1624,1625,1626,1627,1631,1632,1633,1634,1635,1636,1637],{"id":32,"depth":86,"text":33},{"id":107,"depth":86,"text":108},{"id":166,"depth":86,"text":167},{"id":431,"depth":86,"text":432,"children":1628},[1629,1630],{"id":516,"depth":142,"text":517},{"id":631,"depth":142,"text":632},{"id":685,"depth":86,"text":686},{"id":1030,"depth":86,"text":1031},{"id":1215,"depth":86,"text":1216},{"id":1280,"depth":86,"text":1281},{"id":1412,"depth":86,"text":1413},{"id":1458,"depth":86,"text":1459},{"id":1555,"depth":86,"text":1556},"tutorial",{"title":1616,"description":1640,"label":1615,"to":1617,"icon":1614},"Diseñamos e implementamos la infraestructura web de tu aplicación — Nginx, SSL, balanceo de carga y alta disponibilidad.","2026-02-25","Guía paso a paso para configurar Nginx como proxy inverso con certificados SSL de Let's Encrypt para exponer aplicaciones web de forma segura en producción.",false,"md",[1646,1649,1652,1655],{"question":1647,"answer":1648},"¿Qué es un reverse proxy y para qué sirve?","Un reverse proxy es un servidor que se coloca frente a tus aplicaciones y recibe todas las peticiones de los usuarios. Nginx recibe la petición, la reenvía a la aplicación interna (que puede correr en cualquier puerto) y devuelve la respuesta. Esto permite manejar SSL en un solo lugar, balancear carga entre varias réplicas, cachear respuestas y ocultar los puertos internos de tus aplicaciones.",{"question":1650,"answer":1651},"¿Los certificados de Let's Encrypt son seguros para producción?","Sí. Los certificados de Let's Encrypt usan la misma criptografía que los certificados de pago. La diferencia es que son gratuitos, se renuevan automáticamente cada 90 días y no incluyen garantía financiera (que en la práctica nadie usa). Google, Facebook y millones de sitios los usan en producción.",{"question":1653,"answer":1654},"¿Puedo usar Nginx para balancear carga entre varias réplicas?","Sí. Nginx soporta balanceo de carga round-robin, por peso, por IP hash y least connections. Solo defines un bloque upstream con las direcciones de tus réplicas y Nginx distribuye el tráfico automáticamente.",{"question":1656,"answer":1657},"¿Nginx o Apache — cuál debería usar?","Para reverse proxy y servir sitios estáticos, Nginx es superior — usa menos memoria, maneja más conexiones concurrentes y su configuración para proxy es más limpia. Apache sigue siendo válido si necesitas .htaccess o módulos específicos de Apache, pero para arquitecturas modernas con contenedores y microservicios, Nginx es el estándar.","/images/blog/nginx-reverse-proxy.jpg","Diagrama de arquitectura mostrando Nginx como reverse proxy con SSL frente a múltiples aplicaciones backend",{},"/blog/tutorial/nginx-reverse-proxy-ssl",{"title":5,"description":1642},"blog/tutorial/nginx-reverse-proxy-ssl",[525,1665,1666,1667,1668,1638],"ssl","reverse-proxy","lets-encrypt","linux","pjgUDMeoftinHNEkPH_l98RKyMwN2gvtlvTmOnTnJBM",{"path":1671,"title":1672},"/blog/tutorial/docker-compose-guia-completa","Docker Compose para principiantes — guía completa con ejemplos",{"path":1674,"title":1675},"/blog/tutorial/traefik-reverse-proxy-docker","Configurar Traefik como reverse proxy para contenedores Docker",[1677,1684,1691],{"path":1678,"title":1679,"description":1680,"date":1681,"category":1638,"image":1682,"imageAlt":1683,"readingTime":270},"/blog/tutorial/apis-rest-python-fastapi","Crear APIs REST con Python y FastAPI para integraciones empresariales","Guía paso a paso para construir una API REST profesional con Python y FastAPI que conecte tu ERP, CRM o cualquier sistema con validación, autenticación y documentación automática.","2026-03-04","/images/blog/fastapi-api-rest.jpg","Editor de código mostrando una API FastAPI con documentación Swagger generada automáticamente",{"path":1685,"title":1686,"description":1687,"date":1688,"category":1638,"image":1689,"imageAlt":1690,"readingTime":247},"/blog/tutorial/configurar-firewall-ufw-linux","Configurar firewall en Linux con UFW — reglas esenciales","Guía paso a paso para configurar UFW (Uncomplicated Firewall) en Ubuntu y Debian con las reglas esenciales para proteger servidores de producción.","2026-03-01","/images/blog/ufw-firewall-linux.jpg","Terminal de Linux mostrando reglas de firewall UFW activas protegiendo un servidor de producción",{"path":1674,"title":1675,"description":1692,"date":1693,"category":1638,"image":1694,"imageAlt":1695,"readingTime":258},"Guía paso a paso para instalar Traefik como reverse proxy con descubrimiento automático de contenedores Docker, SSL con Let's Encrypt y dashboard de monitoreo.","2026-02-28","/images/blog/traefik-docker.jpg","Dashboard de Traefik mostrando rutas automáticas hacia múltiples contenedores Docker con SSL activo"]