Qué vas a conseguir
Publicar una aplicación interna (la de fichajes, en 127.0.0.1:8080) detrás de Nginx o Apache: con su nombre, HTTPS, las cabeceras que la aplicación necesita, timeouts pensados y logs que dicen cuánto tardó el backend. Y, cuando aparezca el 502 Bad Gateway, saber en cinco minutos si es la aplicación, SELinux o un timeout.
Antes de empezar
- Un servidor RHEL 9 (o Ubuntu) con Nginx o Apache: uno de los dos en el 443, no ambos.
- Dónde está cada cosa: Nginx en
/etc/nginx/conf.d/*.confy logs en/var/log/nginx/. Apache en RHEL en/etc/httpd/conf.d/con logs en/var/log/httpd/; en Debian y Ubuntu en/etc/apache2/sites-available/, que se activa cona2ensite, y logs en/var/log/apache2/. - El nombre en DNS:
fichajes.corp.exampleapuntando al servidor. - El certificado: de la CA corporativa (certificado, cadena intermedia y clave) para nombres internos, o de Let's Encrypt si el nombre es público.
1. Un sitio por nombre: server blocks y virtual hosts
Nginx elige el bloque server por server_name; Apache, el VirtualHost por ServerName. El puerto 80 solo redirige:
server { listen 80; server_name fichajes.corp.example; return 301 https://$host$request_uri;}server { listen 443 ssl; server_name fichajes.corp.example; ssl_certificate /etc/pki/tls/certs/fichajes-fullchain.pem; ssl_certificate_key /etc/pki/tls/private/fichajes.key; ssl_protocols TLSv1.2 TLSv1.3; access_log /var/log/nginx/fichajes.access.log upstream; error_log /var/log/nginx/fichajes.error.log; location / { proxy_pass http://127.0.0.1:8080; include /etc/nginx/proxy-headers.conf; }}<VirtualHost *:80> ServerName fichajes.corp.example Redirect permanent / https://fichajes.corp.example/</VirtualHost><VirtualHost *:443> ServerName fichajes.corp.example SSLEngine on SSLCertificateFile /etc/pki/tls/certs/fichajes-fullchain.pem SSLCertificateKeyFile /etc/pki/tls/private/fichajes.key ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ connectiontimeout=5 timeout=60 ProxyPassReverse / http://127.0.0.1:8080/ RequestHeader set X-Forwarded-Proto "https" ErrorLog /var/log/httpd/fichajes_error.log CustomLog /var/log/httpd/fichajes_access.log proxy</VirtualHost>- Un nombre que no coincide con ningún sitio cae en el sitio por defecto:
default_serveren Nginx, el primerVirtualHostdel puerto en Apache.apachectl -Slos lista. - El formato
upstreamdel log de acceso y elproxyde Apache se definen en el apartado 5: sin ellos, el test de configuración falla.
2. TLS: certificado corporativo o Let's Encrypt
- El fichero del certificado lleva primero el del servidor y después los intermedios. Sin el intermedio, el navegador de IT, que lo tiene en caché, funciona; el móvil de un usuario, no.
- En Apache 2.4.8 y posteriores,
SSLCertificateFileadmite la cadena completa;SSLCertificateChainFileestá obsoleto. - La clave privada con permisos
600. En RHEL, Apache necesitamod_ssl. - Let's Encrypt con certbot:
certbot --nginx -d fichajes.example.com(o--apache) emite, configura y deja programada la renovación. Hoy los certificados duran 90 días y Let's Encrypt ya ha anunciado que irán siendo más cortos: la renovación tiene que ser automática, nunca manual. Comprueba que funciona concertbot renew --dry-run.
openssl s_client -connect fichajes.corp.example:443 -servername fichajes.corp.example </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -enddatesubject=CN = fichajes.corp.exampleissuer=CN = Contoso Issuing CA 01notAfter=Sep 14 23:59:59 2027 GMTSin -servername (SNI) verás el certificado del sitio por defecto.
3. El proxy inverso: las cabeceras
La aplicación ve todas las peticiones llegar desde 127.0.0.1. Para saber el nombre que pidió el usuario, su IP y que venía por HTTPS, el proxy se lo dice en cabeceras:
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_http_version 1.1;- Sin
HostyX-Forwarded-Proto, la aplicación redirige ahttp://127.0.0.1:8080/loginy el usuario acaba en una página que no carga. En Apache,ProxyPreserveHost Onpasa elHost,ProxyPassReversereescribe las redirecciones ymod_proxyañadeX-Forwarded-Forpor su cuenta.
4. Timeouts
| Qué controla | Nginx (por defecto) | Apache (por defecto) |
|---|---|---|
| Conectar con el backend | proxy_connect_timeout (60 s) | connectiontimeout= en ProxyPass |
| Esperar la respuesta | proxy_read_timeout (60 s) | timeout= en ProxyPass, o ProxyTimeout; si no, Timeout (60 s) |
| Tamaño máximo de una subida | client_max_body_size (1 MB) | LimitRequestBody |
- La conexión, corta (5 segundos): si el backend no acepta en ese tiempo, no lo va a hacer. La lectura, la que necesite la página más lenta de verdad, y solo en la
locationde esa página, no en todo el sitio. - Un fichero de más de 1 MB en Nginx devuelve 413 antes de llegar a la aplicación.
5. Logs que sirven
El log de acceso por defecto no dice cuánto tardó el backend. Añádelo en /etc/nginx/nginx.conf, dentro de http:
log_format upstream '$remote_addr [$time_local] "$request" $status $body_bytes_sent ' 'rt=$request_time uct=$upstream_connect_time urt=$upstream_response_time ' 'us=$upstream_status ua=$upstream_addr';rtes el tiempo total yurtel del backend: sirtes alto yurtbajo, el lento es el cliente o la red, no la aplicación.us=-indica que la petición ni siquiera llegó al backend.- En Apache,
%D(microsegundos) da el tiempo total:LogFormat "%h %t \"%r\" %>s %b %D" proxy. - El log de errores (
error_log,ErrorLog) es donde aparece la causa de un 502. Es lo primero que se abre.
6. Probar y aplicar: configtest, reload o restart
sudo nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successfulsudo systemctl reload nginxsudo apachectl configtestSyntax OKsudo systemctl reload httpd- Siempre el test antes.
nginx -Tvuelca la configuración completa con todos losinclude. - reload relee la configuración sin cortar: Nginx arranca procesos nuevos y deja terminar a los viejos; en Apache es un reinicio graceful. Si la configuración nueva tiene un error, Nginx sigue con la anterior.
- restart para y arranca: corta las conexiones abiertas. Solo cuando el proceso no responde o tras una actualización del paquete.
7. El ticket: "la aplicación de fichajes da 502 Bad Gateway"
Lunes, 9:02. Toda la plantilla ficha a la vez y la página devuelve 502 Bad Gateway. Un 502 lo genera el proxy: Nginx funciona, lo que falla es la conexión con el backend. El log de errores dice cuál de los casos es:
sudo tail -n 3 /var/log/nginx/fichajes.error.log2026/10/26 09:02:11 [error] 2211#2211: *8812 connect() failed (111: Connection refused) while connecting to upstream, client: 10.20.4.37, server: fichajes.corp.example, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/"ss -ltnp | grep 8080systemctl status fichajes --no-pagerActive: failed (Result: oom-kill) since Mon 2026-10-26 08:58:40 CET111: Connection refused: nadie escucha en el 8080.ssno devuelve nada y el servicio de la aplicación ha muerto por falta de memoria. Se arranca, se confirma que responde (curl -I http://127.0.0.1:8080/) y se abre un ticket con el equipo de la aplicación con la hora deloom-kill.13: Permission deniedwhile connecting to upstream, en un RHEL recién montado y con el backend escuchando: es SELinux.ausearch -m avc -ts recentmuestra eldenied { name_connect }denginx(ohttpd). La solución essetsebool -P httpd_can_network_connect 1, nosetenforce 0. En Apache aparece como(13)Permission denied: AH00957.- 504 Gateway Time-out, solo en el informe mensual:
upstream timed out (110: Connection timed out) while reading response header from upstreamyurt=60.001. El backend tarda más queproxy_read_timeout: se sube a 300 s solo enlocation /informes/y se pide que el informe sea asíncrono. En Apache esAH01102: error reading status line from remote server.
Antes de tocar el proxy, curl -I http://127.0.0.1:8080/ desde el propio servidor. Si el backend no responde ahí, el proxy no tiene nada que arreglar.
Siguientes pasos
- La guía de Red Hat Enterprise Linux del Nivel 2 explica los servicios, el cortafuegos y SELinux que aparecen en el ticket.
- La de Docker cubre las aplicaciones en contenedores que suelen estar detrás de este proxy.
- La de IIS es la versión Windows de todo esto: sitios, enlaces, certificados y el 503.
- Vigilar desde fuera que el certificado no caduca y que el sitio responde es lo que hacen las sondas TLS y HTTP del repositorio 08-edge-health-slo-monitor de mi GitHub.
¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.
Tech Career Lab · newsletter
¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.
Apúntate y llévate las 33 ideas →