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:
VERSION=$(curl -fsSL https://api.github.com/repos/oauth2-proxy/oauth2-proxy/releases/latest | grep -Po '"tag_name": "\K[^"]+')
echo "$VERSION"
v7.x.y
Descarga el paquete para x86_64 junto con su suma de comprobación y verifica que la descarga está íntegra:
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"
oauth2-proxy-v7.x.y.linux-amd64.tar.gz: OK
Extrae el paquete e instala el binario en /usr/local/bin:
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:
oauth2-proxy --version
oauth2-proxy v7.x.y (built with go1.x.x)
Crea un usuario de sistema sin shell para ejecutar el servicio:
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.
Importantela 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:
openssl rand -base64 32 | tr -- '+/' '-_'
kR3mX0v9b7Qw2zL1yP5sN8tE4uH6jA0cD2fG3hJ5kL8=
Crea el directorio de configuración y abre el archivo:
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:
# 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_orglimita el acceso a los miembros de esa organización. Para restringirlo a un equipo añadegithub_team = "nombre-del-equipo".reverse_proxy = truehace que OAuth2 Proxy confíe en las cabecerasX-Forwarded-*yX-Real-IPque 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 = truedevuelve el usuario y el correo en las cabecerasX-Auth-Request-UseryX-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:
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:
sudo nano /etc/systemd/system/oauth2-proxy.service
[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:
sudo systemctl daemon-reload
sudo systemctl enable --now oauth2-proxy
Comprueba que está en marcha y que responde en su endpoint de salud:
systemctl status oauth2-proxy --no-pager
curl http://127.0.0.1:4180/ping
● 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:
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:
sudo nano /etc/nginx/sites-available/app.your_domain
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:
sudo ln -s /etc/nginx/sites-available/app.your_domain /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
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:
sudo certbot --nginx -d app.your_domain
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:
curl -s -o /dev/null -w '%{http_code}\n' https://app.your_domain/
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:
- Aparece la página de OAuth2 Proxy con el botón Sign in with GitHub.
- 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.
- Tras autorizar vuelves a
https://app.your_domainy vesHola 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:
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:
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:
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.
