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—or worse, lacks native Two-Factor Authentication (2FA) support. Managing fragmented passwords across dozens of admin dashboards creates immense security vulnerability.
Authelia is an open-source, lightweight authentication and authorization server that integrates seamlessly with Nginx using the auth_request 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.
In this cybersecurity tutorial, we will configure Authelia on Ubuntu 24.04/22.04 LTS using Docker Compose, secure private subdomains via Nginx auth_request, and configure TOTP Two-Factor Authentication.
Step 1: Installing Docker and Creating Project Directory
# Install Docker and prerequisite utilities
sudo apt update && sudo apt install -y curl nginx certbot python3-certbot-nginx
curl -fsSL https://get.docker.com | sudo sh
sudo systemctl enable --now docker
# Create project directory
sudo mkdir -p /var/www/authelia
sudo chown -R $USER:$USER /var/www/authelia
cd /var/www/authelia
Step 2: Writing Production Authelia Configuration
Create configuration directory and file /var/www/authelia/configuration.yml:
server:
host: 0.0.0.0
port: 9091
log:
level: info
jwt_secret: "YourUltraSecureJwtSecretKeyAtLeast32Chars!"
default_redirection_url: "https://auth.example.com"
totp:
issuer: "CpanelFree Cloud"
authentication_backend:
file:
path: /config/users_database.yml
access_control:
default_policy: deny
rules:
# Require Two-Factor Authentication for all internal dashboards
- domain: "*.example.com"
policy: two_factor
session:
name: authelia_session
domain: example.com
secret: "AnotherUltraSecureSessionSecretKey32Chars!"
expiration: 3600 # 1 hour
storage:
local:
path: /config/db.sqlite3
notifier:
filesystem:
filename: /config/notification.txt
Step 3: Creating Users Database with Password Hashes
Generate a secure Argon2id password hash using Docker:
# Generate Argon2 password hash
docker run authelia/authelia:latest authelia crypto hash generate argon2 --password "StrongUserPassword2026!"
Create /var/www/authelia/users_database.yml:
users:
admin:
displayname: "Administrator"
password: "$argon2id$v=19$m=65536,t=3,p=4$..."
email: "[email protected]"
groups:
- admins
Step 4: Launching Authelia Container Stack
Create /var/www/authelia/docker-compose.yml:
services:
authelia:
image: authelia/authelia:latest
container_name: authelia_sso
restart: always
ports:
- "127.0.0.1:9091:9091"
volumes:
- ./:/config
deploy:
resources:
limits:
memory: 256M
Launch the container: docker compose up -d.
Step 5: Nginx Forward-Auth Integration & Subdomain Protection
Create the universal Authelia forward-auth snippet at /etc/nginx/snippets/authelia.conf:
location /authelia {
internal;
proxy_pass http://127.0.0.1:9091/api/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
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;
}
Now, protect ANY internal subdomain (e.g. status.example.com or monitor.example.com) by adding two lines:
server {
listen 80;
server_name status.example.com;
# Include Authelia 2FA gatekeeper
include snippets/authelia.conf;
auth_request /authelia;
error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
location / {
proxy_pass http://127.0.0.1:3001;
}
}
Integrating Duo Push & WebAuthn YubiKey Hardware Keys
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.
Enforcing Granular Access Control Policies by User Group
Define role-based access rules in /var/www/authelia/configuration.yml so that only members of the admins group can access critical monitoring and database dashboards, while standard users access general internal tools with single-factor authentication:
access_control:
default_policy: deny
rules:
# Restrict server monitoring dashboards to admins group only
- domain: "monitor.example.com"
subject: "group:admins"
policy: two_factor
# Allow general staff to access status portals with single-factor
- domain: "status.example.com"
subject: "group:staff"
policy: one_factor
Enforcing OpenID Connect (OIDC) Identity Provider (IdP)
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:
# Enable OpenID Connect in /var/www/authelia/configuration.yml
identity_providers:
oidc:
hmac_secret: "YourUltraSecureOidcHmacSecretKey32Chars!"
issuer_private_key: |
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
clients:
- client_id: "grafana"
client_name: "Grafana Monitoring Dashboard"
client_secret: "$argon2id$v=19$m=65536,t=3,p=4$..."
public: false
authorization_policy: "two_factor"
redirect_uris:
- "https://monitor.example.com/login/generic_oauth"
scopes:
- "openid"
- "profile"
- "email"
- "groups"
Authelia Security Hardening Checklist
- Enforce Argon2id Hashing: Always use Argon2id with
m=65536, t=3, p=4parameters for resistant password storage against GPU cracking. - Enable Session Cookie Protection: Ensure
same_site: "lax"andsecure: trueare active.
Protecting Multiple Subdomains with Authelia Regex Wildcards
Instead of manually writing separate server blocks for every internal tool, configure Nginx and Authelia with regex wildcard rules to secure all *.internal.example.com subdomains under a single unified Single Sign-On session:
# Authelia Wildcard Domain Rule (/var/www/authelia/configuration.yml)
access_control:
default_policy: deny
rules:
- domain: "*.internal.example.com"
policy: two_factor
Authelia Session Management & Redis Cluster Storage
For high-availability multi-node VPS clusters, replace local SQLite session storage with in-memory Redis clustering in configuration.yml to allow seamless failover across multiple Authelia instances without forcing users to re-authenticate.
Recommended Related Technical Guides
Fortress-Grade Identity Security on CpanelFree
Protect your infrastructure with zero-trust Single Sign-On, dedicated NVMe servers, and 100% free hosting and VPS options.
🔗 Recommended Related Technical Guides:
- How to Secure Your Linux VPS: 7 Essential Hardening Steps (2026)
- How to Configure UFW Firewall on Ubuntu Server (Rules, Ports & Best Practices)
- How to Install and Configure Fail2ban on Linux (Stop SSH Brute-Force Attacks)
- How to Deploy SurrealDB Multi-Model Database on Ubuntu Linux VPS
- Explore $0 Free cPanel Web Hosting Plans (NVMe SSD, AutoSSL)
Deploy Fast, Reliable Web Hosting on CpanelFree
Get genuine cPanel control, unmetered NVMe SSD storage, and free AutoSSL at $0 cost forever.

