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
|
## 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
|
```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
|
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
|
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
|
mkdir -p authelia/secrets
|
||||||
openssl rand -hex 32 > authelia/secrets/JWT_SECRET
|
openssl rand -hex 32 > authelia/secrets/JWT_SECRET
|
||||||
openssl rand -hex 32 > authelia/secrets/SESSION_SECRET
|
openssl rand -hex 32 > authelia/secrets/SESSION_SECRET
|
||||||
openssl rand -hex 32 > authelia/secrets/STORAGE_ENCRYPTION_KEY
|
openssl rand -hex 32 > authelia/secrets/STORAGE_ENCRYPTION_KEY
|
||||||
chmod 600 authelia/secrets/*
|
chmod 600 authelia/secrets/*
|
||||||
|
```
|
||||||
|
|
||||||
# 3) Copy and edit .env -- this is the only place you set your domain.
|
### 3. Set your domain
|
||||||
# DOMAIN flows into authelia/configuration.yml and caddy/Caddyfile
|
|
||||||
# automatically via each tool's env-var substitution; no find-and-replace.
|
`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
|
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
|
```bash
|
||||||
# matching rule in authelia/configuration.yml under access_control.rules.
|
$EDITOR .env
|
||||||
#
|
```
|
||||||
# WHY: default_policy is 'deny'. If a domain reaches Authelia with no
|
|
||||||
# matching rule, Authelia returns 403 -- even to a logged-in user. The
|
Set `DOMAIN=yourdomain.com` and `TZ=Your/Timezone`. Save and close.
|
||||||
# rule tells Authelia the domain is valid and what auth level to require.
|
|
||||||
#
|
### 4. Add access control rules
|
||||||
# Each rule is two lines -- just uncomment and pick one_factor or two_factor:
|
|
||||||
# - domain: 'cam.{{ env "DOMAIN" }}'
|
**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.**
|
||||||
# policy: 'two_factor'
|
|
||||||
|
```bash
|
||||||
$EDITOR authelia/configuration.yml
|
$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
|
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 \
|
docker compose run --rm authelia \
|
||||||
authelia crypto hash generate argon2 --password 'your-real-password'
|
authelia crypto hash generate argon2 --password 'your-real-password'
|
||||||
# Paste the $argon2id$... output into the password: field.
|
```
|
||||||
|
|
||||||
# 6) Pre-create the Authelia log file.
|
Copy the `$argon2id$...` line and paste it as the `password:` value in `users_database.yml`.
|
||||||
# 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.
|
### 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
|
touch authelia/authelia.log
|
||||||
|
```
|
||||||
|
|
||||||
# 7) Validate config before starting.
|
### 7. Validate the config
|
||||||
|
|
||||||
|
```bash
|
||||||
docker compose run --rm authelia \
|
docker compose run --rm authelia \
|
||||||
authelia validate-config --config /config/configuration.yml
|
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
|
## Wire Caddy into Authelia
|
||||||
|
|
||||||
Open `caddy/snippets.caddyfile`. It contains copy-paste blocks for your
|
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:
|
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
|
```yaml
|
||||||
auth:
|
auth:
|
||||||
enabled: False
|
enabled: False
|
||||||
trusted_proxies:
|
trusted_proxies:
|
||||||
- 172.18.0.0/16 # the caddy_net subnet -- find it with:
|
- 172.18.0.0/16 # replace with your caddy_net subnet from above
|
||||||
# docker network inspect caddy_net | jq '.[0].IPAM.Config'
|
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
header_map:
|
header_map:
|
||||||
@@ -410,21 +506,28 @@ proxy:
|
|||||||
default_role: viewer
|
default_role: viewer
|
||||||
separator: '|'
|
separator: '|'
|
||||||
# Optional shared secret -- prevents LAN header spoofing.
|
# 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'
|
# auth_secret: 'your-32-byte-hex'
|
||||||
```
|
```
|
||||||
|
|
||||||
Then uncomment `cam.example.com` in `authelia/configuration.yml`, restart
|
To generate the optional `auth_secret`:
|
||||||
both services:
|
|
||||||
|
```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
|
```bash
|
||||||
docker compose restart authelia
|
docker compose restart authelia
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
docker compose restart frigate # in your Frigate stack
|
docker compose restart frigate # in your Frigate stack
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify: `https://cam.example.com` in a private window goes to Authelia and
|
Verify in a private browser window: `https://cam.yourdomain.com` should go to Authelia and back without a Frigate login screen.
|
||||||
back without a Frigate login screen.
|
|
||||||
|
|
||||||
## First login + TOTP enrollment
|
## First login + TOTP enrollment
|
||||||
|
|
||||||
@@ -545,18 +648,26 @@ notifier:
|
|||||||
# password loaded via AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
|
# password loaded via AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
|
||||||
```
|
```
|
||||||
|
|
||||||
Add the secret and wire it up:
|
Add the secret file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo 'your_smtp_password' > authelia/secrets/SMTP_PASSWORD
|
echo 'your_smtp_password' > authelia/secrets/SMTP_PASSWORD
|
||||||
chmod 600 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
|
```yaml
|
||||||
- AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/secrets/SMTP_PASSWORD
|
- 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
|
## 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
|
### "access denied" with no login prompt
|
||||||
|
|
||||||
`default_policy: deny` and no `access_control` rule for this domain. Add a
|
`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`:
|
||||||
rule in `authelia/configuration.yml` and restart Authelia.
|
|
||||||
|
```yaml
|
||||||
|
- domain: 'yoursite.{{ env "DOMAIN" }}'
|
||||||
|
policy: 'two_factor'
|
||||||
|
```
|
||||||
|
|
||||||
|
Then restart Authelia:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose restart authelia
|
||||||
|
```
|
||||||
|
|
||||||
### Authelia container restarts forever
|
### 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 can't resolve `authelia`
|
||||||
|
|
||||||
Caddy isn't on `caddy_net`. Add `networks: [caddy_net]` to your Caddy
|
Caddy isn't on `caddy_net`. Add this to your Caddy service in its compose file:
|
||||||
service and `caddy_net: external: true` at the bottom of its compose, then:
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
networks:
|
||||||
|
- caddy_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
caddy_net:
|
||||||
|
external: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then recreate the Caddy container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d caddy
|
docker compose up -d caddy
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user