ติดตั้ง Authelia: 2FA + SSO สำหรับ VPS Linux
Authelia คือ authentication server แบบ open-source ที่ให้คุณเพิ่ม Two-Factor Authentication (2FA) และ Single Sign-On (SSO) ให้กับทุกแอปพลิเคชันที่รันบน VPS ของคุณ โดยทำงานร่วมกับ reverse proxy อย่าง Nginx หรือ Traefik ได้อย่างลงตัว
แทนที่แต่ละแอปจะต้องจัดการ login ของตัวเอง Authelia ทำหน้าที่เป็น "ประตูรักษาความปลอดภัย" กลาง — ผู้ใช้ login ครั้งเดียว ได้สิทธิ์เข้าถึงทุก service ที่อนุญาต พร้อม 2FA ป้องกันการเข้าถึงโดยไม่ได้รับอนุญาต
ทำไมต้องใช้ Authelia?
| คุณสมบัติ | รายละเอียด |
|---|---|
| Single Sign-On | Login ครั้งเดียว เข้าถึงทุก service |
| 2FA/MFA | รองรับ TOTP (Google Authenticator), WebAuthn, Push notification |
| Access Control | กำหนด policy ละเอียดถึง path-level |
| Brute-Force Protection | ล็อก account หลัง login ผิดซ้ำ |
| Open Source | ฟรี self-hosted ไม่มีค่าใช้จ่ายรายเดือน |
สิ่งที่ต้องเตรียมก่อนเริ่ม
- VPS Ubuntu 22.04/24.04 หรือ Debian 12
- Docker และ Docker Compose ติดตั้งแล้ว
- Nginx หรือ Traefik เป็น reverse proxy
- Domain และ Wildcard SSL certificate (เช่น
*.example.com) - RAM อย่างน้อย 512 MB สำหรับ Authelia + Redis
โครงสร้าง Authelia ที่จะติดตั้ง
เราจะใช้ Docker Compose รัน Authelia คู่กับ Redis (สำหรับ session) และ LLDAP (สำหรับจัดการ user) ทั้งหมดอยู่หลัง Nginx reverse proxy
VPS
├── Nginx (reverse proxy + auth_request)
│ ├── authelia.example.com → Authelia
│ ├── app1.example.com → App1 (protected)
│ └── app2.example.com → App2 (protected)
└── Docker Compose
├── authelia (authentication server)
├── redis (session storage)
└── lldap (user directory)
ขั้นตอนที่ 1: สร้าง Directory Structure
mkdir -p ~/authelia/{config,data}
cd ~/authelia
ขั้นตอนที่ 2: สร้าง docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: unless-stopped
volumes:
- ./config:/config
- ./data:/data
environment:
- AUTHELIA_JWT_SECRET_FILE=/config/jwt_secret
- AUTHELIA_SESSION_SECRET_FILE=/config/session_secret
- AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/config/storage_encryption_key
ports:
- "9091:9091"
depends_on:
- redis
networks:
- authelia_net
redis:
image: redis:7-alpine
container_name: authelia_redis
restart: unless-stopped
volumes:
- redis_data:/data
networks:
- authelia_net
volumes:
redis_data:
networks:
authelia_net:
driver: bridge
EOF
ขั้นตอนที่ 3: สร้าง Secret Files
# สร้าง secret keys แบบสุ่ม
openssl rand -hex 64 > ~/authelia/config/jwt_secret
openssl rand -hex 64 > ~/authelia/config/session_secret
openssl rand -hex 64 > ~/authelia/config/storage_encryption_key
chmod 600 ~/authelia/config/*_secret ~/authelia/config/storage_encryption_key
ขั้นตอนที่ 4: สร้าง configuration.yml
cat > ~/authelia/config/configuration.yml << 'EOF'
server:
host: 0.0.0.0
port: 9091
log:
level: info
theme: light
jwt_secret_file: /config/jwt_secret
default_redirection_url: https://example.com
totp:
issuer: example.com
period: 30
skew: 1
authentication_backend:
file:
path: /config/users_database.yml
password:
algorithm: bcrypt
iterations: 12
access_control:
default_policy: deny
rules:
# เปิดให้ทุกคนเข้า public area
- domain: "www.example.com"
policy: bypass
# ต้องการ 2FA สำหรับ admin tools
- domain: "*.example.com"
subject: "group:admins"
policy: two_factor
# ต้องการแค่ login สำหรับ user ทั่วไป
- domain: "app1.example.com"
subject: "group:users"
policy: one_factor
session:
name: authelia_session
secret_file: /config/session_secret
expiration: 1h
inactivity: 15m
domain: example.com
redis:
host: redis
port: 6379
regulation:
max_retries: 5
find_time: 2m
ban_time: 10m
storage:
local:
path: /data/db.sqlite3
encryption_key_file: /config/storage_encryption_key
notifier:
filesystem:
filename: /data/notification.txt
EOF
example.com ด้วย domain จริงของคุณทุกจุด สำหรับ production ควรใช้ SMTP notifier แทน filesystemขั้นตอนที่ 5: สร้าง Users Database
# สร้าง password hash สำหรับ user
docker run --rm authelia/authelia:latest authelia hash-password 'your_secure_password'
# ได้ผลลัพธ์ เช่น: $argon2id$v=19$m=65536,t=3,p=4$...
cat > ~/authelia/config/users_database.yml << 'EOF'
users:
admin:
displayname: "Administrator"
password: "$argon2id$v=19$m=65536,t=3,p=4$YOUR_HASH_HERE"
email: [email protected]
groups:
- admins
- users
alice:
displayname: "Alice"
password: "$argon2id$v=19$m=65536,t=3,p=4$ALICE_HASH_HERE"
email: [email protected]
groups:
- users
EOF
ขั้นตอนที่ 6: ตั้งค่า Nginx
เพิ่ม location block สำหรับ Authelia และ auth_request ให้ทุก virtual host ที่ต้องการป้องกัน
# /etc/nginx/snippets/authelia.conf
location /internal/authelia/authz {
internal;
proxy_pass http://127.0.0.1:9091/api/authz/auth-request;
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-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
# /etc/nginx/sites-available/app1.example.com
server {
listen 443 ssl http2;
server_name app1.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/snippets/authelia.conf;
location / {
auth_request /internal/authelia/authz;
auth_request_set $target_url $scheme://$http_host$request_uri;
error_page 401 =302 https://authelia.example.com/?rd=$target_url;
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Virtual host สำหรับ Authelia เอง
server {
listen 443 ssl http2;
server_name authelia.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9091;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
ขั้นตอนที่ 7: Start Authelia
cd ~/authelia
docker compose up -d
# ดู logs
docker compose logs -f authelia
ขั้นตอนที่ 8: ตั้งค่า TOTP (2FA)
เมื่อ login ครั้งแรก Authelia จะให้ลงทะเบียน TOTP QR code ให้สแกนด้วย Google Authenticator หรือ Authy ได้เลย
# ตรวจสอบว่า user ลงทะเบียน TOTP แล้ว
docker exec authelia authelia storage user totp export --config /config/configuration.yml
ตรวจสอบว่า Authelia ทำงานถูกต้อง
# ตรวจสอบ container กำลังรัน
docker compose ps
# ทดสอบ health endpoint
curl -s http://127.0.0.1:9091/api/health | python3 -m json.tool
# ตรวจสอบ Redis connection
docker exec authelia_redis redis-cli ping
# ดู Authelia logs แบบ real-time
docker compose logs -f authelia --tail=50
# ทดสอบ auth endpoint (ควรได้ 401 เพราะไม่มี session)
curl -I http://127.0.0.1:9091/api/authz/auth-request
docker compose logs authelia — ปัญหาที่พบบ่อยคือ permission ของ config files หรือ secret files ไม่ถูกต้อง ให้รัน chmod 600 ~/authelia/config/*แก้ปัญหาที่พบบ่อย
Error: "level=fatal msg=\"configuration: secrets: error loading secret\""
ไฟล์ secret มี permission ไม่ถูกต้อง หรือ Authelia container อ่านไม่ได้
# แก้ permission
chmod 600 ~/authelia/config/jwt_secret
chmod 600 ~/authelia/config/session_secret
chmod 600 ~/authelia/config/storage_encryption_key
# restart container
docker compose restart authelia
Error: "dial tcp redis:6379: connect: connection refused"
Redis container ยังไม่พร้อม หรือชื่อ service ใน docker-compose ไม่ตรงกับ configuration.yml
# ตรวจสอบชื่อ service Redis ใน docker-compose.yml
docker compose ps
# ชื่อใน session.redis.host ต้องตรงกับชื่อ service
# รัน Redis แยกก่อน
docker compose up -d redis
sleep 3
docker compose up -d authelia
Error: "auth_request module returned 500"
Nginx ติดต่อ Authelia ไม่ได้ หรือ proxy_pass URL ไม่ถูกต้อง
# ตรวจสอบว่า Authelia bind ที่ port 9091
ss -tlnp | grep 9091
# ตรวจสอบ nginx config
nginx -t
# ดู nginx error log
tail -50 /var/log/nginx/error.log
Error: "level=error msg=\"session: error reading session\""
Session secret เปลี่ยนแปลงหลัง restart ทำให้ session เก่าอ่านไม่ได้
# ล้าง Redis session ทั้งหมด (user ต้อง login ใหม่)
docker exec authelia_redis redis-cli FLUSHDB
docker compose restart authelia
Error: "totp: failed to verify code"
นาฬิกา server กับมือถือคลาดเคลื่อนเกิน 30 วินาที
# ตรวจสอบเวลา server
timedatectl status
# ซิงค์เวลา
timedatectl set-ntp true
# หรือบังคับ sync
chronyc makestep
คำถามที่พบบ่อย
Authelia ต่างจาก Keycloak อย่างไร?
Authelia เน้นความเบาและง่าย เหมาะกับ VPS resource น้อย ใช้ config file แทน database และรองรับ 2FA + SSO ผ่าน reverse proxy โดยตรง ส่วน Keycloak ครอบคลุม feature มากกว่า (SAML, OAuth2 server เต็มรูปแบบ) แต่กิน RAM สูงกว่ามาก (512MB ขึ้นไป)
ใช้ Authelia กับ Traefik ได้ไหม?
ได้ และ Traefik รองรับ Authelia แบบ native ผ่าน forwardAuth middleware เพียงเพิ่ม labels ใน docker-compose ของแต่ละ service แทนการแก้ไข config file ทำให้ง่ายกว่าใช้กับ Nginx มาก
ถ้า Authelia ล่มแล้วจะเข้า service ได้ไหม?
ไม่ได้ เพราะ auth_request ของ Nginx จะ return error เมื่อ upstream ตอบไม่ได้ วิธีแก้คือรัน Authelia บน Docker Swarm หรือตั้ง restart: always และ health check ใน docker-compose เพื่อให้ container restart อัตโนมัติเมื่อล่ม