docs: break first-run into individual copyable steps; clarify two-sided gate
- First-run setup: replace one big bash comment block with numbered sub-sections, each step getting its own prose explanation and separate code block(s) so individual commands can be copied without selecting around surrounding lines - Step 4: add explicit table showing what happens when each side of the Caddy/Authelia gate is missing; add policy comparison table - Frigate section: move subnet discovery command out of YAML comment into its own code block; separate restart commands into own blocks - Troubleshooting "access denied": show the exact rule YAML to add and the restart command, each in their own block - Troubleshooting "Caddy can't resolve authelia": show full compose YAML snippet rather than describing it in prose - SMTP section: separate each action into its own code block https://claude.ai/code/session_012eTokAaGiZo7aGt1T2W9BC
This commit is contained in:
@@ -281,68 +281,157 @@ gh auth login
|
||||
|
||||
## First-run setup
|
||||
|
||||
### 0. Clone the repo
|
||||
|
||||
The Frigate stack lives on `main`. This auth stack is on the `authelia` branch -- clone it separately into its own directory.
|
||||
|
||||
```bash
|
||||
git clone -b authelia \
|
||||
https://github.com/outis1one/frigate_w_audio.git \
|
||||
~/docker/authelia
|
||||
```
|
||||
|
||||
```bash
|
||||
# 0) Clone the auth stack onto the server.
|
||||
# (The Frigate stack lives on the `main` branch and is cloned separately.)
|
||||
gh repo clone outis1one/frigate_w_audio -- \
|
||||
--branch authelia ~/docker/authelia
|
||||
cd ~/docker/authelia
|
||||
```
|
||||
|
||||
# 1) Create the external docker network (Caddy must also be on this).
|
||||
### 1. Create the external Docker network
|
||||
|
||||
Caddy must join this same network so it can reach Authelia by container name. Skip if `caddy_net` already exists.
|
||||
|
||||
```bash
|
||||
docker network create caddy_net 2>/dev/null || true
|
||||
```
|
||||
|
||||
# 2) Bootstrap the secrets directory.
|
||||
### 2. Generate secrets
|
||||
|
||||
Authelia loads these from files so they never appear in `docker inspect` or process listings.
|
||||
|
||||
```bash
|
||||
mkdir -p authelia/secrets
|
||||
openssl rand -hex 32 > authelia/secrets/JWT_SECRET
|
||||
openssl rand -hex 32 > authelia/secrets/SESSION_SECRET
|
||||
openssl rand -hex 32 > authelia/secrets/STORAGE_ENCRYPTION_KEY
|
||||
chmod 600 authelia/secrets/*
|
||||
```
|
||||
|
||||
# 3) Copy and edit .env -- this is the only place you set your domain.
|
||||
# DOMAIN flows into authelia/configuration.yml and caddy/Caddyfile
|
||||
# automatically via each tool's env-var substitution; no find-and-replace.
|
||||
### 3. Set your domain
|
||||
|
||||
`DOMAIN` is the only value you set here. It flows into `authelia/configuration.yml` via Go template substitution and into your Caddyfile via `{env.DOMAIN}` -- no find-and-replace needed anywhere else.
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
$EDITOR .env # set DOMAIN, TZ; pin image versions if you want
|
||||
```
|
||||
|
||||
# 4) For each site you added `import authelia` to in Caddy, uncomment the
|
||||
# matching rule in authelia/configuration.yml under access_control.rules.
|
||||
#
|
||||
# WHY: default_policy is 'deny'. If a domain reaches Authelia with no
|
||||
# matching rule, Authelia returns 403 -- even to a logged-in user. The
|
||||
# rule tells Authelia the domain is valid and what auth level to require.
|
||||
#
|
||||
# Each rule is two lines -- just uncomment and pick one_factor or two_factor:
|
||||
# - domain: 'cam.{{ env "DOMAIN" }}'
|
||||
# policy: 'two_factor'
|
||||
```bash
|
||||
$EDITOR .env
|
||||
```
|
||||
|
||||
Set `DOMAIN=yourdomain.com` and `TZ=Your/Timezone`. Save and close.
|
||||
|
||||
### 4. Add access control rules
|
||||
|
||||
**This step and step 8 (Caddy wiring) must be done together for every site you want to gate. Both are required -- neither alone is enough.**
|
||||
|
||||
```bash
|
||||
$EDITOR authelia/configuration.yml
|
||||
```
|
||||
|
||||
# 5) Create your first user.
|
||||
Scroll to `access_control.rules`. Uncomment the rule for each site you want to protect and choose a policy:
|
||||
|
||||
```yaml
|
||||
- domain: 'cam.{{ env "DOMAIN" }}'
|
||||
policy: 'two_factor'
|
||||
```
|
||||
|
||||
#### Why both sides are required
|
||||
|
||||
Caddy and Authelia each control one half of the gate:
|
||||
|
||||
| What you configure | What it does |
|
||||
|--------------------|-------------|
|
||||
| `import authelia` in a Caddy site block | Sends that site's requests to Authelia for a decision |
|
||||
| Rule in `access_control.rules` | Tells Authelia what decision to make |
|
||||
|
||||
The default policy is `deny`. If a request reaches Authelia with no matching rule, it gets a **403 Forbidden -- no login prompt, no redirect, just blocked**. This is true even for an already-logged-in user.
|
||||
|
||||
Miss either side and here is what happens:
|
||||
|
||||
| Caddy `import authelia` | Rule in `configuration.yml` | Result |
|
||||
|------------------------|----------------------------|--------|
|
||||
| Missing | Present | Site is open -- Authelia is never consulted |
|
||||
| Present | Missing | 403 Forbidden, no login prompt |
|
||||
| Both missing | | Site is open -- Authelia is never consulted |
|
||||
| Both present | | Works correctly |
|
||||
|
||||
#### Which policy to use
|
||||
|
||||
| Policy | Requires |
|
||||
|--------|---------|
|
||||
| `bypass` | Nothing -- Authelia waves the request through. Used for the portal itself only. |
|
||||
| `one_factor` | Password only |
|
||||
| `two_factor` | Password + TOTP. Use this for everything. |
|
||||
|
||||
### 5. Create your first user
|
||||
|
||||
```bash
|
||||
cp authelia/users_database.yml.example authelia/users_database.yml
|
||||
$EDITOR authelia/users_database.yml # set username, email, displayname
|
||||
```
|
||||
|
||||
# Generate the password hash:
|
||||
```bash
|
||||
$EDITOR authelia/users_database.yml
|
||||
```
|
||||
|
||||
Fill in `username`, `email`, and `displayname`. Then generate the password hash:
|
||||
|
||||
```bash
|
||||
docker compose run --rm authelia \
|
||||
authelia crypto hash generate argon2 --password 'your-real-password'
|
||||
# Paste the $argon2id$... output into the password: field.
|
||||
```
|
||||
|
||||
# 6) Pre-create the Authelia log file.
|
||||
# Docker creates a DIRECTORY at the bind-mount path if the file doesn't
|
||||
# exist, which breaks fail2ban's mount. Create it as an empty file first.
|
||||
Copy the `$argon2id$...` line and paste it as the `password:` value in `users_database.yml`.
|
||||
|
||||
### 6. Pre-create the Authelia log file
|
||||
|
||||
Docker creates a **directory** at a bind-mount path if the source file does not exist yet. That breaks fail2ban's read-only mount. Create it as an empty file first:
|
||||
|
||||
```bash
|
||||
touch authelia/authelia.log
|
||||
```
|
||||
|
||||
# 7) Validate config before starting.
|
||||
### 7. Validate the config
|
||||
|
||||
```bash
|
||||
docker compose run --rm authelia \
|
||||
authelia validate-config --config /config/configuration.yml
|
||||
# Expect: "Configuration: validation complete" with no errors.
|
||||
|
||||
# 8) Wire up Caddy (see "Wire Caddy into Authelia" below).
|
||||
|
||||
# 9) Bring it up.
|
||||
docker compose up -d
|
||||
docker compose logs -f authelia # expect "Authelia is listening on ..."
|
||||
docker compose logs -f fail2ban # expect "Jail authelia is now active"
|
||||
```
|
||||
|
||||
Expect: `Configuration: validation complete` with no errors. Fix any YAML issues before continuing.
|
||||
|
||||
### 8. Wire Caddy
|
||||
|
||||
See [Wire Caddy into Authelia](#wire-caddy-into-authelia) below. Add the Caddy site block for each site alongside the rule you added in step 4.
|
||||
|
||||
### 9. Bring it up
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Confirm both services started cleanly:
|
||||
|
||||
```bash
|
||||
docker compose logs -f authelia
|
||||
```
|
||||
|
||||
Expect: `Authelia is listening on ...`
|
||||
|
||||
```bash
|
||||
docker compose logs -f fail2ban
|
||||
```
|
||||
|
||||
Expect: `Jail authelia is now active`
|
||||
|
||||
## Wire Caddy into Authelia
|
||||
|
||||
Open `caddy/snippets.caddyfile`. It contains copy-paste blocks for your
|
||||
@@ -396,12 +485,19 @@ sudo chown caddy:caddy /var/log/caddy # adjust to your Caddy UID
|
||||
|
||||
Edit `frigate_config/config.yml` in your Frigate stack:
|
||||
|
||||
First, find your `caddy_net` subnet -- you need this for `trusted_proxies`:
|
||||
|
||||
```bash
|
||||
docker network inspect caddy_net | jq '.[0].IPAM.Config'
|
||||
```
|
||||
|
||||
Then edit `frigate_config/config.yml`:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
enabled: False
|
||||
trusted_proxies:
|
||||
- 172.18.0.0/16 # the caddy_net subnet -- find it with:
|
||||
# docker network inspect caddy_net | jq '.[0].IPAM.Config'
|
||||
- 172.18.0.0/16 # replace with your caddy_net subnet from above
|
||||
|
||||
proxy:
|
||||
header_map:
|
||||
@@ -410,21 +506,28 @@ proxy:
|
||||
default_role: viewer
|
||||
separator: '|'
|
||||
# Optional shared secret -- prevents LAN header spoofing.
|
||||
# Generate: openssl rand -hex 32
|
||||
# Set the same value as `header_up X-Proxy-Secret` in caddy/Caddyfile.
|
||||
# auth_secret: 'your-32-byte-hex'
|
||||
```
|
||||
|
||||
Then uncomment `cam.example.com` in `authelia/configuration.yml`, restart
|
||||
both services:
|
||||
To generate the optional `auth_secret`:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
Set the same value in the `header_up X-Proxy-Secret` line in your Caddy site block.
|
||||
|
||||
Add the rule to `authelia/configuration.yml` (step 4 of first-run), then restart both services:
|
||||
|
||||
```bash
|
||||
docker compose restart authelia
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose restart frigate # in your Frigate stack
|
||||
```
|
||||
|
||||
Verify: `https://cam.example.com` in a private window goes to Authelia and
|
||||
back without a Frigate login screen.
|
||||
Verify in a private browser window: `https://cam.yourdomain.com` should go to Authelia and back without a Frigate login screen.
|
||||
|
||||
## First login + TOTP enrollment
|
||||
|
||||
@@ -545,18 +648,26 @@ notifier:
|
||||
# password loaded via AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
|
||||
```
|
||||
|
||||
Add the secret and wire it up:
|
||||
Add the secret file:
|
||||
|
||||
```bash
|
||||
echo 'your_smtp_password' > authelia/secrets/SMTP_PASSWORD
|
||||
chmod 600 authelia/secrets/SMTP_PASSWORD
|
||||
```
|
||||
|
||||
Add to the authelia service environment in `docker-compose.yml`:
|
||||
Add to the `authelia` service `environment:` block in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
- AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/secrets/SMTP_PASSWORD
|
||||
```
|
||||
|
||||
Restart and look for `"Notifier SMTP startup check successful"` in logs.
|
||||
Restart and check for a successful startup message:
|
||||
|
||||
```bash
|
||||
docker compose restart authelia && docker compose logs -f authelia
|
||||
```
|
||||
|
||||
Expect: `Notifier SMTP startup check successful`
|
||||
|
||||
## Security notes
|
||||
|
||||
@@ -581,8 +692,18 @@ of it served over HTTPS. Mixed HTTP/HTTPS won't work; the session cookie is
|
||||
|
||||
### "access denied" with no login prompt
|
||||
|
||||
`default_policy: deny` and no `access_control` rule for this domain. Add a
|
||||
rule in `authelia/configuration.yml` and restart Authelia.
|
||||
`default_policy: deny` -- a request reached Authelia with no matching rule for that domain. Add a rule under `access_control.rules` in `authelia/configuration.yml`:
|
||||
|
||||
```yaml
|
||||
- domain: 'yoursite.{{ env "DOMAIN" }}'
|
||||
policy: 'two_factor'
|
||||
```
|
||||
|
||||
Then restart Authelia:
|
||||
|
||||
```bash
|
||||
docker compose restart authelia
|
||||
```
|
||||
|
||||
### Authelia container restarts forever
|
||||
|
||||
@@ -595,8 +716,21 @@ Most often: missing/empty secret files in `authelia/secrets/`, bad YAML in
|
||||
|
||||
### Caddy can't resolve `authelia`
|
||||
|
||||
Caddy isn't on `caddy_net`. Add `networks: [caddy_net]` to your Caddy
|
||||
service and `caddy_net: external: true` at the bottom of its compose, then:
|
||||
Caddy isn't on `caddy_net`. Add this to your Caddy service in its compose file:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
caddy:
|
||||
networks:
|
||||
- caddy_net
|
||||
|
||||
networks:
|
||||
caddy_net:
|
||||
external: true
|
||||
```
|
||||
|
||||
Then recreate the Caddy container:
|
||||
|
||||
```bash
|
||||
docker compose up -d caddy
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user