Enam aplikasi self-hosted biasanya berarti enam halaman login, enam password berbeda, dan enam kesempatan untuk akhirnya memakai password yang sama di semuanya. Authelia memotong angka itu jadi satu: kita masuk sekali di auth.domain-kita.com, lalu Nextcloud, Gitea, Portainer, dan panel lainnya membuka pintu sendiri karena sudah percaya pada Authelia. Bukan karena aplikasinya diubah, tetapi karena Nginx yang bertanya lebih dulu ke Authelia sebelum meneruskan request.
Oke, lanjuutt.. Di artikel ini kita akan memasang Authelia di VPS (versi stabil 4.39.28, rilis 17 September 2026) dengan penyimpanan SQLite, user dari file YAML, dan forward auth di Nginx yang sudah jalan di host. Semua perintah di bawah bisa diikuti dari nol, tanpa panel dan tanpa layanan pihak ketiga.
Kenapa Authelia di VPS Cocok untuk Lab Self-Hosted
Ada dua cara populer menaruh login terpusat di depan aplikasi: OpenID Connect dan forward auth. OIDC lebih rapi, tapi aplikasinya harus mendukung OIDC — dan banyak panel self-hosted kecil belum. Forward auth bekerja di lapisan proxy, jadi aplikasi apa pun yang bisa diproksikan Nginx ikut terlindungi tanpa disentuh.
Yang kita dapat dengan pendekatan ini:
- Satu sesi untuk banyak domain. Cookie
contoh.comberlaku untuknextcloud.contoh.comdangitea.contoh.comsekaligus. - 2FA sekali pasang. TOTP didaftarkan di Authelia, bukan di tiap aplikasi yang belum tentu punya fitur itu.
- Aturan akses per domain. Panel admin bisa dipaksa
two_factor, sementara aplikasi internal cukupone_factor, atau bahkan dibuka hanya untuk jaringan tertentu. - Satu tempat untuk mencabut akses. Hapus user di
users.yml, seluruh aplikasi ikut menolak.
Batasnya juga perlu jujur: forward auth hanya melindungi trafik yang lewat proxy. Kalau port 8081 aplikasi masih terbuka ke internet, orang bisa melewati Authelia sepenuhnya. Jadi tutup port aplikasi dan biarkan hanya Nginx yang bicara ke 127.0.0.1.
Yang Perlu Disiapkan
- VPS dengan Docker dan Docker Compose (Ubuntu 24.04/26.04 sudah cukup).
- Dua nama domain:
auth.contoh.comuntuk portal, dan satu aplikasi uji misalnyanextcloud.contoh.com. - Nginx di host plus sertifikat TLS — Authelia wajib diakses lewat HTTPS, ini keputusan desain mereka, bukan saran.
- Port
9091tidak dibuka ke publik. Cukup127.0.0.1.
Langkah 1 — Siapkan Folder dan Tiga Secret
Authelia butuh tiga nilai acak: penanda JWT reset password, secret sesi, dan kunci enkripsi database. Jangan pakai kata sandi buatan sendiri.
mkdir -p ~/authelia/config
cd ~/authelia
docker run --rm authelia/authelia:4.39.28 \
authelia crypto rand --length 64 --charset alphanumeric
Jalankan tiga kali, lalu simpan hasilnya sebagai JWT_SECRET, SESSION_SECRET, dan STORAGE_ENCRYPTION_KEY. Nilai SESSION_SECRET sebaiknya 64 karakter atau lebih, dan STORAGE_ENCRYPTION_KEY minimal 20 karakter — lebih panjang lebih baik, karena kunci ini mengenkripsi kolom sensitif di database.
Langkah 2 — Buat User dan Hash Password-nya
Password di users.yml disimpan sebagai hash argon2id, bukan teks biasa. Authelia menyediakan perintahnya sendiri:
docker run --rm -it authelia/authelia:4.39.28 \
authelia crypto hash generate argon2 --password 'PasswordKuatKita123!'
Salin bagian Digest: $argon2id$... ke file config/users.yml:
---
users:
donny:
disabled: false
displayname: 'Donny'
password: '$argon2id$v=19$m=65536,t=3,p=4$GANTI_DENGAN_HASH_KITA'
email: '[email protected]'
groups:
- 'admins'
Kalau nanti menambah user, cukup tambahkan blok baru di level yang sama dan biarkan watch: true yang kita pasang di langkah berikut memuat ulang file tanpa restart container.
Langkah 3 — Tulis configuration.yml
Ini inti pemasangannya. Simpan sebagai config/configuration.yml, lalu chmod 600 karena di dalamnya ada tiga secret.
---
server:
address: 'tcp://:9091/'
endpoints:
authz:
auth-request:
implementation: 'AuthRequest'
log:
level: 'info'
identity_validation:
reset_password:
jwt_secret: 'JWT_SECRET_DARI_LANGKAH_1'
authentication_backend:
file:
path: '/config/users.yml'
watch: true
password:
algorithm: 'argon2'
argon2:
variant: 'argon2id'
iterations: 3
memory: 65536
parallelism: 4
key_length: 32
salt_length: 16
access_control:
default_policy: 'deny'
rules:
- domain: 'auth.contoh.com'
policy: 'bypass'
- domain: 'panel.contoh.com'
policy: 'two_factor'
- domain: '*.contoh.com'
policy: 'one_factor'
session:
secret: 'SESSION_SECRET_DARI_LANGKAH_1'
cookies:
- domain: 'contoh.com'
authelia_url: 'https://auth.contoh.com'
default_redirection_url: 'https://nextcloud.contoh.com'
regulation:
max_retries: 3
find_time: '2 minutes'
ban_time: '5 minutes'
storage:
encryption_key: 'STORAGE_ENCRYPTION_KEY_DARI_LANGKAH_1'
local:
path: '/config/db.sqlite3'
notifier:
filesystem:
filename: '/config/notification.txt'
totp:
issuer: 'contoh.com'
Tiga hal yang paling sering salah di blok ini:
- Baris pertama
access_controlwajibbypassuntuk domain portal. Kalauauth.contoh.comikut diproteksi, Authelia akan meminta login untuk halaman login — lingkaran yang tidak ada ujungnya. domaindi sesi adalah domain induk, bukanauth.contoh.com. Cookie harus bisa dibaca seluruh subdomain;authelia_urlboleh subdomain.- Urutan aturan berpengaruh. Aturan pertama yang cocok yang dipakai, jadi taruh yang paling spesifik di atas.
storage.local memakai SQLite karena kita hanya menjalankan satu instance. Dokumentasi Authelia menyebut SQLite cocok untuk deployment ringan dan menyarankan PostgreSQL untuk produksi ber-HA — untuk satu VPS pribadi, satu file db.sqlite3 yang ikut ter-backup justru lebih simpel.
Langkah 4 — Jalankan dengan Docker Compose
---
services:
authelia:
container_name: 'authelia'
image: 'authelia/authelia:4.39.28'
restart: 'unless-stopped'
volumes:
- './config:/config'
ports:
- '127.0.0.1:9091:9091'
docker compose up -d
docker compose logs -f authelia
Tunggu sampai log berhenti di baris Authelia is listening for non-TLS connections on 127.0.0.1:9091. Kalau muncul error soal konfigurasi, Authelia menolak start dan menyebut nama field-nya — baca dari atas, bukan dari bawah.
Langkah 5 — Sambungkan Nginx ke Authelia
Kita butuh dua snippet. Yang pertama membuat endpoint internal yang dipanggil Nginx untuk setiap request:
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 Connection "";
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Original-URL $scheme://$host$request_uri;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-URI $request_uri;
proxy_http_version 1.1;
}
Yang kedua dipasang di dalam location aplikasi yang dilindungi:
# /etc/nginx/snippets/authelia-authrequest.conf
auth_request /internal/authelia/authz;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $email $upstream_http_remote_email;
auth_request_set $name $upstream_http_remote_name;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Email $email;
proxy_set_header Remote-Name $name;
auth_request_set $redirection_url $upstream_http_location;
error_page 401 =302 $redirection_url;
Lalu server block aplikasi:
server {
listen 443 ssl http2;
server_name nextcloud.contoh.com;
ssl_certificate /etc/letsencrypt/live/contoh.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/contoh.com/privkey.pem;
include /etc/nginx/snippets/authelia-location.conf;
location / {
include /etc/nginx/snippets/authelia-authrequest.conf;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:8081;
}
}
Dua baris terakhir di snippet authrequest adalah bagian yang paling sering terlupa. Tanpa error_page 401 =302 $redirection_url, pengunjung tidak diarahkan ke portal — mereka hanya melihat halaman 401 kosong dan mengira situsnya rusak.
sudo nginx -t && sudo systemctl reload nginx
Langkah 6 — Uji Sebelum Percaya
Urutan pengujian yang membuktikan semuanya bekerja:
- Buka
https://auth.contoh.com— harus muncul halaman login Authelia, bukan 502. - Masuk dengan user dari
users.yml, lalu daftarkan TOTP lewat aplikasi authenticator. Kode cadangan yang ditampilkan sebaiknya disimpan. - Buka
https://nextcloud.contoh.comdi jendela incognito. Kita harus dilempar ke portal lebih dulu, baru setelah login diteruskan ke Nextcloud. - Masuk ke
panel.contoh.comdan pastikan diminta kode TOTP, karena aturannyatwo_factorsedangkan domain lainone_factor. - Cek
docker compose logs authelia— setiap keputusan authorize tercatat, jadi kita bisa melihat domain mana yang ditolak dan alasannya.
Kalau langkah 3 berhasil tetapi aset halaman (CSS/gambar) ikut terlempar ke portal, biasanya ada request lintas domain dari aplikasi. Solusinya bukan mematikan auth, tapi menambah aturan bypass untuk resources tertentu, misalnya path /static atau endpoint health check yang memang tidak sensitif.
Kesalahan yang Sering Makan Waktu
- Portal ditaruh di belakang autentikasi Authelia sendiri. Pastikan
auth.contoh.compunya aturanbypassdi urutan pertama. - Cookie tidak terbaca antar subdomain.
domainharuscontoh.com, danauthelia_urlharus HTTPS. - Port aplikasi masih terbuka. Forward auth hanya menjaga jalur proxy; tutup
8081dari publik. - Mengubah
STORAGE_ENCRYPTION_KEYsetelah database terisi. Data sensitif jadi tidak bisa didekripsi. Ganti hanya lewat prosedur CLI resmi, bukan dengan mengedit YAML. - **Lupa
X-Forwarded-*.** Authelia memakai header itu untuk membangun URL redirect; tanpa itu, login bisa berhasil tetapi kita dilempar ke alamat yang salah.
Kesimpulan
Authelia bukan alat yang memasang login di dalam aplikasi kita — ia berdiri di depan pintu dan memeriksa siapa yang datang. Dengan satu container, satu file konfigurasi, dan dua snippet Nginx, seluruh lab self-hosted bisa berbagi satu sesi, satu 2FA, dan satu kebijakan akses. Biaya RAM-nya kecil, dan yang paling penting: tidak ada lagi panel yang lupa kita kunci karena malas mengingat password ke sepuluh tempat berbeda.
Mulai dari satu aplikasi dulu — pilih yang paling sensitif — lalu tambahkan domain lain satu per satu. Setiap penambahan hanya butuh satu baris di access_control dan satu include di Nginx, jadi tidak ada alasan menunda sampai semuanya “siap”.

