{"id":1924,"date":"2026-09-05T10:23:17","date_gmt":"2026-09-05T04:53:17","guid":{"rendered":"https:\/\/cpanelfree.com\/blog\/how-to-setup-authelia-two-factor-sso-reverse-proxy-vps\/"},"modified":"2026-09-05T13:00:11","modified_gmt":"2026-09-05T07:30:11","slug":"how-to-setup-authelia-two-factor-sso-reverse-proxy-vps","status":"publish","type":"post","link":"https:\/\/cpanelfree.com\/blog\/how-to-setup-authelia-two-factor-sso-reverse-proxy-vps\/","title":{"rendered":"How to Set Up Authelia Single Sign-On (SSO) and 2FA with Nginx on Ubuntu VPS"},"content":{"rendered":"<h2>Why Self-Hosted Web Portals Need Centralized Zero-Trust 2FA<\/h2>\n<p>As you self-host multiple internal web applications on your Linux VPS (such as Uptime Kuma, Glances, Portainer, MinIO Console, Traefik Dashboard, or phpMyAdmin), each platform features its own separate authentication mechanism\u2014or worse, lacks native Two-Factor Authentication (2FA) support. Managing fragmented passwords across dozens of admin dashboards creates immense security vulnerability.<\/p>\n<p><strong>Authelia<\/strong> is an open-source, lightweight authentication and authorization server that integrates seamlessly with Nginx using the <code>auth_request<\/code> forward-authentication module. Authelia acts as a fortress gatekeeper in front of all your subdomains: unauthenticated visitors are automatically redirected to a sleek Single Sign-On (SSO) portal requiring a primary password and secondary 2FA (TOTP authenticator app, WebAuthn YubiKey, or Duo push) before Nginx permits traffic through.<\/p>\n<p>In this cybersecurity tutorial, we will configure Authelia on Ubuntu 24.04\/22.04 LTS using Docker Compose, secure private subdomains via Nginx <code>auth_request<\/code>, and configure TOTP Two-Factor Authentication.<\/p>\n<h2>Step 1: Installing Docker and Creating Project Directory<\/h2>\n<pre><code># Install Docker and prerequisite utilities\nsudo apt update &amp;&amp; sudo apt install -y curl nginx certbot python3-certbot-nginx\ncurl -fsSL https:\/\/get.docker.com | sudo sh\nsudo systemctl enable --now docker\n\n# Create project directory\nsudo mkdir -p \/var\/www\/authelia\nsudo chown -R $USER:$USER \/var\/www\/authelia\ncd \/var\/www\/authelia<\/code><\/pre>\n<h2>Step 2: Writing Production Authelia Configuration<\/h2>\n<p>Create configuration directory and file <code>\/var\/www\/authelia\/configuration.yml<\/code>:<\/p>\n<pre><code>server:\n  host: 0.0.0.0\n  port: 9091\n\nlog:\n  level: info\n\njwt_secret: \"YourUltraSecureJwtSecretKeyAtLeast32Chars!\"\ndefault_redirection_url: \"https:\/\/auth.example.com\"\n\ntotp:\n  issuer: \"CpanelFree Cloud\"\n\nauthentication_backend:\n  file:\n    path: \/config\/users_database.yml\n\naccess_control:\n  default_policy: deny\n  rules:\n    # Require Two-Factor Authentication for all internal dashboards\n    - domain: \"*.example.com\"\n      policy: two_factor\n\nsession:\n  name: authelia_session\n  domain: example.com\n  secret: \"AnotherUltraSecureSessionSecretKey32Chars!\"\n  expiration: 3600 # 1 hour\n\nstorage:\n  local:\n    path: \/config\/db.sqlite3\n\nnotifier:\n  filesystem:\n    filename: \/config\/notification.txt<\/code><\/pre>\n<h2>Step 3: Creating Users Database with Password Hashes<\/h2>\n<p>Generate a secure Argon2id password hash using Docker:<\/p>\n<pre><code># Generate Argon2 password hash\ndocker run authelia\/authelia:latest authelia crypto hash generate argon2 --password \"StrongUserPassword2026!\"<\/code><\/pre>\n<p>Create <code>\/var\/www\/authelia\/users_database.yml<\/code>:<\/p>\n<pre><code>users:\n  admin:\n    displayname: \"Administrator\"\n    password: \"$argon2id$v=19$m=65536,t=3,p=4$...\"\n    email: \"admin@example.com\"\n    groups:\n      - admins<\/code><\/pre>\n<h2>Step 4: Launching Authelia Container Stack<\/h2>\n<p>Create <code>\/var\/www\/authelia\/docker-compose.yml<\/code>:<\/p>\n<pre><code>services:\n  authelia:\n    image: authelia\/authelia:latest\n    container_name: authelia_sso\n    restart: always\n    ports:\n      - \"127.0.0.1:9091:9091\"\n    volumes:\n      - .\/:\/config\n    deploy:\n      resources:\n        limits:\n          memory: 256M<\/code><\/pre>\n<p>Launch the container: <code>docker compose up -d<\/code>.<\/p>\n<h2>Step 5: Nginx Forward-Auth Integration &amp; Subdomain Protection<\/h2>\n<p>Create the universal Authelia forward-auth snippet at <code>\/etc\/nginx\/snippets\/authelia.conf<\/code>:<\/p>\n<pre><code>location \/authelia {\n    internal;\n    proxy_pass http:\/\/127.0.0.1:9091\/api\/verify;\n    proxy_pass_request_body off;\n    proxy_set_header Content-Length \"\";\n    proxy_set_header X-Original-URL $scheme:\/\/$http_host$request_uri;\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}<\/code><\/pre>\n<p>Now, protect ANY internal subdomain (e.g. <code>status.example.com<\/code> or <code>monitor.example.com<\/code>) by adding two lines:<\/p>\n<pre><code>server {\n    listen 80;\n    server_name status.example.com;\n\n    # Include Authelia 2FA gatekeeper\n    include snippets\/authelia.conf;\n    auth_request \/authelia;\n\n    error_page 401 =302 https:\/\/auth.example.com\/?rd=$scheme:\/\/$http_host$request_uri;\n\n    location \/ {\n        proxy_pass http:\/\/127.0.0.1:3001;\n    }\n}<\/code><\/pre>\n<h2>Integrating Duo Push &amp; WebAuthn YubiKey Hardware Keys<\/h2>\n<p>Authelia natively supports FIDO2 WebAuthn cryptographic hardware security keys (YubiKey, Google Titan) and Duo mobile push notifications for enterprise Two-Factor Authentication. Users can register their biometric TouchID, Windows Hello, or YubiKey directly within the Authelia self-service security portal.<\/p>\n<h2>Enforcing Granular Access Control Policies by User Group<\/h2>\n<p>Define role-based access rules in <code>\/var\/www\/authelia\/configuration.yml<\/code> so that only members of the <code>admins<\/code> group can access critical monitoring and database dashboards, while standard users access general internal tools with single-factor authentication:<\/p>\n<pre><code>access_control:\n  default_policy: deny\n  rules:\n    # Restrict server monitoring dashboards to admins group only\n    - domain: \"monitor.example.com\"\n      subject: \"group:admins\"\n      policy: two_factor\n\n    # Allow general staff to access status portals with single-factor\n    - domain: \"status.example.com\"\n      subject: \"group:staff\"\n      policy: one_factor<\/code><\/pre>\n<h2>Enforcing OpenID Connect (OIDC) Identity Provider (IdP)<\/h2>\n<p>Authelia can function as a full OpenID Connect (OIDC) Identity Provider, allowing third-party applications (such as Grafana, Nextcloud, Forgejo, or Portainer) to delegate authentication to Authelia using OAuth2 tokens:<\/p>\n<pre><code># Enable OpenID Connect in \/var\/www\/authelia\/configuration.yml\nidentity_providers:\n  oidc:\n    hmac_secret: \"YourUltraSecureOidcHmacSecretKey32Chars!\"\n    issuer_private_key: |\n      -----BEGIN RSA PRIVATE KEY-----\n      ...\n      -----END RSA PRIVATE KEY-----\n    clients:\n      - client_id: \"grafana\"\n        client_name: \"Grafana Monitoring Dashboard\"\n        client_secret: \"$argon2id$v=19$m=65536,t=3,p=4$...\"\n        public: false\n        authorization_policy: \"two_factor\"\n        redirect_uris:\n          - \"https:\/\/monitor.example.com\/login\/generic_oauth\"\n        scopes:\n          - \"openid\"\n          - \"profile\"\n          - \"email\"\n          - \"groups\"<\/code><\/pre>\n<h2>Authelia Security Hardening Checklist<\/h2>\n<ul>\n<li><strong>Enforce Argon2id Hashing:<\/strong> Always use Argon2id with <code>m=65536, t=3, p=4<\/code> parameters for resistant password storage against GPU cracking.<\/li>\n<li><strong>Enable Session Cookie Protection:<\/strong> Ensure <code>same_site: \"lax\"<\/code> and <code>secure: true<\/code> are active.<\/li>\n<\/ul>\n<h2>Protecting Multiple Subdomains with Authelia Regex Wildcards<\/h2>\n<p>Instead of manually writing separate server blocks for every internal tool, configure Nginx and Authelia with regex wildcard rules to secure all <code>*.internal.example.com<\/code> subdomains under a single unified Single Sign-On session:<\/p>\n<pre><code># Authelia Wildcard Domain Rule (\/var\/www\/authelia\/configuration.yml)\naccess_control:\n  default_policy: deny\n  rules:\n    - domain: \"*.internal.example.com\"\n      policy: two_factor<\/code><\/pre>\n<h2>Authelia Session Management &amp; Redis Cluster Storage<\/h2>\n<p>For high-availability multi-node VPS clusters, replace local SQLite session storage with in-memory Redis clustering in <code>configuration.yml<\/code> to allow seamless failover across multiple Authelia instances without forcing users to re-authenticate.<\/p>\n<div style=\"background-color: #0f172a;border-left: 4px solid #38bdf8;padding: 18px 24px;margin: 30px 0;border-radius: 8px\">\n<h3 style=\"color: #38bdf8;margin-top: 0\">Recommended Related Technical Guides<\/h3>\n<ul style=\"margin-bottom: 0;color: #cbd5e1\">\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-secure-linux-vps-fail2ban-ufw-ssh\/\" style=\"color: #38bdf8;text-decoration: underline\">Hardening Linux Cloud VPS Infrastructure with UFW<\/a><\/li>\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-setup-hashicorp-vault-secrets-management-vps\/\" style=\"color: #38bdf8;text-decoration: underline\">Setting Up HashiCorp Vault Secrets Management on Linux<\/a><\/li>\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-host-uptime-kuma-server-monitoring-docker-vps\/\" style=\"color: #38bdf8;text-decoration: underline\">Securing Uptime Kuma Dashboards behind Authelia SSO<\/a><\/li>\n<\/ul>\n<\/div>\n<div style=\"background: linear-gradient(135deg, #0284c7 0%, #0369a1 100%);color: #ffffff;padding: 28px;border-radius: 12px;margin: 35px 0;text-align: center\">\n<h3 style=\"color: #ffffff;margin-top: 0;font-size: 22px\">Fortress-Grade Identity Security on CpanelFree<\/h3>\n<p style=\"color: #e0f2fe;font-size: 15px;max-width: 650px;margin: 0 auto 18px auto\">Protect your infrastructure with zero-trust Single Sign-On, dedicated NVMe servers, and 100% free hosting and VPS options.<\/p>\n<p>  <a href=\"https:\/\/cpanelfree.com\/\" style=\"background-color: #ffffff;color: #0284c7;font-weight: 700;padding: 12px 28px;border-radius: 8px;text-decoration: none;display: inline-block\">Get Free Cloud Hosting Today &rarr;<\/a>\n<\/div>\n<div style=\"border-left: 4px solid #38bdf8;border-radius: 8px;padding: 20px;margin: 30px 0\">\n<h3 style=\"margin-top: 0;color: #38bdf8;font-size: 18px;display: flex;align-items: center\">\n        <span style=\"margin-right: 8px\">\ud83d\udd17<\/span> Recommended Related Technical Guides:<br \/>\n    <\/h3>\n<ul style=\"margin: 10px 0 0 0;padding-left: 20px;line-height: 1.8\">\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-secure-linux-vps-hardening-guide\/\" style=\"color: #38bdf8;text-decoration: none;font-weight: 600\">How to Secure Your Linux VPS: 7 Essential Hardening Steps (2026)<\/a><\/li>\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-configure-ufw-firewall-ubuntu\/\" style=\"color: #38bdf8;text-decoration: none;font-weight: 600\">How to Configure UFW Firewall on Ubuntu Server (Rules, Ports &amp; Best Practices)<\/a><\/li>\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-install-configure-fail2ban-linux\/\" style=\"color: #38bdf8;text-decoration: none;font-weight: 600\">How to Install and Configure Fail2ban on Linux (Stop SSH Brute-Force Attacks)<\/a><\/li>\n<li><a href=\"https:\/\/cpanelfree.com\/blog\/how-to-deploy-surrealdb-multi-model-database-ubuntu-vps\/\" style=\"color: #38bdf8;text-decoration: none;font-weight: 600\">How to Deploy SurrealDB Multi-Model Database on Ubuntu Linux VPS<\/a><\/li>\n<li><a href=\"https:\/\/cpanelfree.com\/#plans\" style=\"color: #10b981;text-decoration: none;font-weight: 600\">Explore $0 Free cPanel Web Hosting Plans (NVMe SSD, AutoSSL)<\/a><\/li>\n<\/ul>\n<\/div>\n<div style=\"background: linear-gradient(135deg, rgba(6, 182, 212, 0.15) 0%, rgba(59, 130, 246, 0.15) 100%);border-radius: 12px;padding: 25px;margin: 30px 0;text-align: center\">\n<h3 style=\"color: #38bdf8;margin-top: 0;font-size: 20px\">Deploy Fast, Reliable Web Hosting on CpanelFree<\/h3>\n<p style=\"color: #94a3b8;font-size: 14px;line-height: 1.6;max-width: 600px;margin: 0 auto 15px\">\n        Get genuine cPanel control, unmetered NVMe SSD storage, and free AutoSSL at $0 cost forever.\n    <\/p>\n<p>    <a href=\"https:\/\/cpanelfree.com\/#plans\" style=\"display: inline-block;background: linear-gradient(135deg, #0284c7 0%, #0369a1 100%);color: #ffffff;padding: 10px 22px;border-radius: 6px;text-decoration: none;font-weight: bold;font-size: 14px\">Claim Free Hosting Account<\/a>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Why Self-Hosted Web Portals Need Centralized Zero-Trust 2FA As you self-host multiple internal web applications on your Linux VPS (such as Uptime Kuma, Glances, Portainer, MinIO Console, Traefik Dashboard, or phpMyAdmin), each platform features its own separate authentication mechanism\u2014or worse, lacks native Two-Factor Authentication (2FA) support. Managing fragmented passwords across dozens of admin dashboards creates [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2519,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[64],"tags":[],"class_list":["post-1924","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security"],"_links":{"self":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts\/1924","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/comments?post=1924"}],"version-history":[{"count":4,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts\/1924\/revisions"}],"predecessor-version":[{"id":2319,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/posts\/1924\/revisions\/2319"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/media\/2519"}],"wp:attachment":[{"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/media?parent=1924"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/categories?post=1924"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cpanelfree.com\/blog\/wp-json\/wp\/v2\/tags?post=1924"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}