--- title: "Cómo proteger una web con OAuth2 Proxy y Nginx en Ubuntu" description: "Instala OAuth2 Proxy en Ubuntu 24.04 como servicio systemd y protege cualquier aplicación web detrás de Nginx con inicio de sesión de GitHub, Google o Keycloak." category: "Gestión de Identidad y Acceso" language: es source: https://cubepath.com/es/docs/gestión-de-identidad-y-acceso/instalacion-de-oauth2-proxy-para-autenticacion updated: 2026-09-25 --- # Cómo proteger una web con OAuth2 Proxy y Nginx en Ubuntu OAuth2 Proxy es un proxy de autenticación que pide a los usuarios iniciar sesión con un proveedor de identidad (GitHub, Google, Keycloak o cualquier servidor OpenID Connect) antes de dejarles llegar a una aplicación web, sin tocar el código de esa aplicación. En este tutorial lo instalarás en Ubuntu 24.04 como servicio systemd y lo conectarás a Nginx mediante `auth_request`, de modo que solo los miembros de tu organización de GitHub puedan abrir `https://app.your_domain`. Al final verás cómo cambiar de proveedor a Google o Keycloak. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, y un usuario no root con privilegios `sudo`. - Un subdominio (en esta guía, **`app.your_domain`**) con un registro DNS A que apunte a la IP pública del servidor. - Nginx y Certbot instalados: `sudo apt install nginx certbot python3-certbot-nginx`. - Puertos 80 y 443 abiertos en UFW: `sudo ufw allow 'Nginx Full'`. - Una aplicación escuchando solo en `127.0.0.1:3000`. Si todavía no tienes una, en el paso 5 se levanta una de prueba. - Una cuenta de GitHub con permisos de administración sobre una organización. ## Paso 1: Instalar el binario de OAuth2 Proxy OAuth2 Proxy se distribuye como un único binario de Go en las releases de GitHub. Consulta la última versión publicada y guárdala en una variable: ```bash VERSION=$(curl -fsSL https://api.github.com/repos/oauth2-proxy/oauth2-proxy/releases/latest | grep -Po '"tag_name": "\K[^"]+') echo "$VERSION" ``` ```output v7.x.y ``` Descarga el paquete para x86_64 junto con su suma de comprobación y verifica que la descarga está íntegra: ```bash cd /tmp curl -fsSLO "https://github.com/oauth2-proxy/oauth2-proxy/releases/download/${VERSION}/oauth2-proxy-${VERSION}.linux-amd64.tar.gz" curl -fsSLO "https://github.com/oauth2-proxy/oauth2-proxy/releases/download/${VERSION}/oauth2-proxy-${VERSION}.linux-amd64.tar.gz-sha256sum.txt" sha256sum -c "oauth2-proxy-${VERSION}.linux-amd64.tar.gz-sha256sum.txt" ``` ```output oauth2-proxy-v7.x.y.linux-amd64.tar.gz: OK ``` Extrae el paquete e instala el binario en `/usr/local/bin`: ```bash tar -xzf "oauth2-proxy-${VERSION}.linux-amd64.tar.gz" sudo install -m 0755 "oauth2-proxy-${VERSION}.linux-amd64/oauth2-proxy" /usr/local/bin/oauth2-proxy ``` En un servidor arm64 sustituye `linux-amd64` por `linux-arm64` en todos los nombres. Comprueba la instalación: ```bash oauth2-proxy --version ``` ```output oauth2-proxy v7.x.y (built with go1.x.x) ``` Crea un usuario de sistema sin shell para ejecutar el servicio: ```bash sudo useradd --system --no-create-home --shell /usr/sbin/nologin oauth2-proxy ``` ## Paso 2: Registrar la aplicación OAuth en GitHub OAuth2 Proxy necesita un Client ID y un Client Secret emitidos por el proveedor. En GitHub, abre la organización y ve a **Settings > Developer settings > OAuth Apps > New OAuth App** y rellena: - **Application name**: un nombre reconocible, por ejemplo `Panel interno`. - **Homepage URL**: `https://app.your_domain` - **Authorization callback URL**: `https://app.your_domain/oauth2/callback` Pulsa **Register application**, copia el **Client ID** y genera un **Client secret** con **Generate a new client secret**. GitHub solo muestra el secreto una vez, así que guárdalo en ese momento. > Importante: la URL de callback debe coincidir exactamente (esquema, host y ruta) con la que configurarás en OAuth2 Proxy. Cualquier diferencia provoca el error `redirect_uri_mismatch`. ## Paso 3: Configurar OAuth2 Proxy OAuth2 Proxy cifra la cookie de sesión con un secreto de 32 bytes. Genéralo con OpenSSL en el formato que espera la herramienta: ```bash openssl rand -base64 32 | tr -- '+/' '-_' ``` ```output kR3mX0v9b7Qw2zL1yP5sN8tE4uH6jA0cD2fG3hJ5kL8= ``` Crea el directorio de configuración y abre el archivo: ```bash sudo mkdir -p /etc/oauth2-proxy sudo nano /etc/oauth2-proxy/oauth2-proxy.cfg ``` Pega esta configuración y sustituye los valores de ejemplo por tu Client ID, tu Client Secret, el secreto de la cookie, tu dominio y el nombre de tu organización: ```ini # Proveedor e identificadores de la OAuth App provider = "github" client_id = "your_client_id" client_secret = "your_client_secret" github_org = "your_github_org" # La autorización se hace por organización, no por dominio de correo email_domains = ["*"] # Escucha solo en local; Nginx es el único que habla con OAuth2 Proxy http_address = "127.0.0.1:4180" reverse_proxy = true redirect_url = "https://app.your_domain/oauth2/callback" # Modo auth_request: OAuth2 Proxy solo valida, Nginx sirve la aplicación upstreams = ["static://202"] set_xauthrequest = true # Cookie de sesión cookie_secret = "your_cookie_secret" cookie_secure = true cookie_expire = "168h" ``` Qué hace cada bloque: - `github_org` limita el acceso a los miembros de esa organización. Para restringirlo a un equipo añade `github_team = "nombre-del-equipo"`. - `reverse_proxy = true` hace que OAuth2 Proxy confíe en las cabeceras `X-Forwarded-*` y `X-Real-IP` que envía Nginx. - `upstreams = ["static://202"]` indica que OAuth2 Proxy no reenvía el tráfico a la aplicación, solo responde 202 a las peticiones autenticadas. Nginx se encarga del resto. - `set_xauthrequest = true` devuelve el usuario y el correo en las cabeceras `X-Auth-Request-User` y `X-Auth-Request-Email`, que Nginx pasará a la aplicación. El archivo contiene secretos, así que restringe los permisos para que solo root y el servicio puedan leerlo: ```bash sudo chown root:oauth2-proxy /etc/oauth2-proxy/oauth2-proxy.cfg sudo chmod 640 /etc/oauth2-proxy/oauth2-proxy.cfg ``` ## Paso 4: Crear el servicio systemd Crea la unidad de systemd: ```bash sudo nano /etc/systemd/system/oauth2-proxy.service ``` ```ini [Unit] Description=OAuth2 Proxy After=network-online.target Wants=network-online.target [Service] User=oauth2-proxy Group=oauth2-proxy ExecStart=/usr/local/bin/oauth2-proxy --config=/etc/oauth2-proxy/oauth2-proxy.cfg Restart=on-failure RestartSec=5 NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true [Install] WantedBy=multi-user.target ``` Recarga systemd, habilita el servicio y arráncalo: ```bash sudo systemctl daemon-reload sudo systemctl enable --now oauth2-proxy ``` Comprueba que está en marcha y que responde en su endpoint de salud: ```bash systemctl status oauth2-proxy --no-pager curl http://127.0.0.1:4180/ping ``` ```output ● oauth2-proxy.service - OAuth2 Proxy Loaded: loaded (/etc/systemd/system/oauth2-proxy.service; enabled; preset: enabled) Active: active (running) ... OK ``` Si el servicio no arranca, `sudo journalctl -u oauth2-proxy -n 50` muestra la opción de configuración que no le gusta. ## Paso 5: Integrar OAuth2 Proxy con Nginx Si aún no tienes una aplicación detrás, levanta un servidor de prueba en otra terminal. Escucha solo en local, así que no es accesible desde fuera: ```bash mkdir -p ~/demo && echo "Hola desde la app protegida" > ~/demo/index.html python3 -m http.server 3000 --bind 127.0.0.1 --directory ~/demo ``` Crea el sitio de Nginx: ```bash sudo nano /etc/nginx/sites-available/app.your_domain ``` ```nginx server { listen 80; server_name app.your_domain; # Rutas propias de OAuth2 Proxy: inicio de sesión, callback y cierre de sesión location /oauth2/ { proxy_pass http://127.0.0.1:4180; 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_set_header X-Auth-Request-Redirect $request_uri; } # Subpetición que valida la sesión; no lleva cuerpo location = /oauth2/auth { internal; proxy_pass http://127.0.0.1:4180; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Uri $request_uri; proxy_set_header Content-Length ""; proxy_pass_request_body off; } location / { auth_request /oauth2/auth; error_page 401 =403 /oauth2/sign_in; # Renueva la cookie cuando OAuth2 Proxy la refresca auth_request_set $auth_cookie $upstream_http_set_cookie; add_header Set-Cookie $auth_cookie; # Identidad del usuario para la aplicación auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email; proxy_set_header X-User $user; proxy_set_header X-Email $email; proxy_pass http://127.0.0.1:3000; 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; } } ``` Nginx consulta `/oauth2/auth` antes de cada petición a `/`. Si OAuth2 Proxy responde 202, la petición sigue hacia la aplicación; si responde 401, Nginx muestra la página de inicio de sesión. La ruta `/oauth2/` queda fuera de `auth_request` a propósito: si la protegieras, el login entraría en bucle. Activa el sitio, comprueba la sintaxis y recarga Nginx: ```bash sudo ln -s /etc/nginx/sites-available/app.your_domain /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` ## Paso 6: Obtener el certificado TLS La cookie de sesión se marca como `Secure` y GitHub exige HTTPS en el callback, así que el sitio debe servirse por HTTPS. Certbot obtiene el certificado de Let's Encrypt y añade al bloque `server` la configuración TLS y la redirección desde HTTP: ```bash sudo certbot --nginx -d app.your_domain ``` ```output Successfully deployed certificate for app.your_domain to /etc/nginx/sites-enabled/app.your_domain Congratulations! You have successfully enabled HTTPS on https://app.your_domain ``` ## Paso 7: Probar el acceso Primero comprueba desde la terminal que una petición sin sesión no llega a la aplicación: ```bash curl -s -o /dev/null -w '%{http_code}\n' https://app.your_domain/ ``` ```output 403 ``` El código 403 corresponde a la página de inicio de sesión de OAuth2 Proxy, no al contenido de la aplicación. Ahora abre `https://app.your_domain` en el navegador: 1. Aparece la página de OAuth2 Proxy con el botón **Sign in with GitHub**. 2. GitHub te pide autorizar la OAuth App. Si la organización tiene restringido el acceso de aplicaciones de terceros, un propietario debe aprobarla en la misma pantalla. 3. Tras autorizar vuelves a `https://app.your_domain` y ves `Hola desde la app protegida`. Con una cuenta que no pertenece a la organización, OAuth2 Proxy muestra un error 403 y no crea la sesión. En el registro del servicio se ve cada intento: ```bash sudo journalctl -u oauth2-proxy -n 20 --no-pager ``` Para cerrar sesión visita `https://app.your_domain/oauth2/sign_out`. ## Usar Google o Keycloak en lugar de GitHub El resto de la configuración (Nginx, systemd, cookie) no cambia. Solo cambian las líneas del proveedor en `/etc/oauth2-proxy/oauth2-proxy.cfg`, y después hay que reiniciar con `sudo systemctl restart oauth2-proxy`. **Google.** En Google Cloud Console crea un ID de cliente OAuth de tipo **Aplicación web** con el URI de redirección `https://app.your_domain/oauth2/callback`. Sustituye `provider`, `github_org` y `email_domains` por: ```ini provider = "google" client_id = "your_client_id.apps.googleusercontent.com" client_secret = "your_client_secret" # Solo cuentas de tu dominio de Google Workspace email_domains = ["your_company.com"] ``` **Keycloak.** Crea en tu realm un cliente OpenID Connect con **Client authentication** activado y `https://app.your_domain/oauth2/callback` como redirect URI válido. Después usa: ```ini provider = "keycloak-oidc" client_id = "oauth2-proxy" client_secret = "your_client_secret" oidc_issuer_url = "https://sso.your_domain/realms/your_realm" email_domains = ["*"] code_challenge_method = "S256" ``` OAuth2 Proxy descubre los endpoints de Keycloak a partir de `oidc_issuer_url`, así que no hace falta indicarlos uno a uno. Si prefieres una lista explícita de personas en vez de una organización o dominio, deja `email_domains = []`, crea `/etc/oauth2-proxy/emails.txt` con un correo por línea y añade `authenticated_emails_file = "/etc/oauth2-proxy/emails.txt"`. ## Solución de problemas **`redirect_uri_mismatch` en el proveedor.** La URL de callback registrada en GitHub, Google o Keycloak no coincide con `redirect_url`. Deben ser idénticas, incluido `https://` y sin barra final. **El servicio no arranca con un error sobre `cookie_secret`.** El secreto debe decodificarse a 16, 24 o 32 bytes. Genera uno nuevo con el comando del paso 3 y pégalo sin espacios ni saltos de línea. **El navegador entra en un bucle de redirecciones.** Suele pasar cuando `auth_request` se aplica también a `/oauth2/`, o cuando el sitio se sirve por HTTP y la cookie `Secure` no se guarda. Revisa que el bloque `location /oauth2/` no tenga `auth_request` y que accedes por HTTPS. **La aplicación no recibe `X-User` ni `X-Email`.** Comprueba que `set_xauthrequest = true` está en la configuración y que reiniciaste el servicio después de cambiarla. ## Conclusión Has instalado OAuth2 Proxy como servicio systemd y lo has conectado a Nginx con `auth_request`, de modo que la aplicación solo es accesible para los miembros autorizados de tu organización de GitHub y recibe la identidad del usuario en cabeceras HTTP. Como siguientes pasos puedes proteger otros subdominios reutilizando los mismos bloques `location`, limitar el acceso a un equipo concreto con `github_team` o centralizar la identidad en un proveedor propio como Keycloak o Authentik.