Merge pull request #195 from outis1one/claude/asterisk-digital-ocean-w22kk8

Claude/asterisk digital ocean w22kk8
This commit is contained in:
Outis
2026-07-20 23:12:44 -04:00
committed by GitHub
2 changed files with 173 additions and 7 deletions
+32
View File
@@ -281,6 +281,38 @@ self-documenting on the deployed box.
Some services have their own login screens; others have none and need Caddy to
gate them via Authelia.
**Protecting more than one apex domain from the same box — same instance, not a second
one.** `services/authelia.sh`, re-run against an existing install, offers "Add another
protected domain to this instance": it appends a new `access_control.rules` entry and a new
`session.cookies` entry (both are YAML lists — Authelia natively supports multiple
independent cookie scopes) plus a Caddy `auth.<domain>` portal block for the new domain, all
on the **same** Authelia + Redis container. Each domain gets its own login/session (no
cross-domain SSO between them) and shares one user database, without the RAM cost of a
second full Authelia+Redis stack — the right choice whenever the domains are going to live
on the same machine anyway. See `add_authelia_domain()` in `services/authelia.sh`.
**Running a genuinely separate instance (e.g. one per machine).** `services/authelia.sh`
runs standalone on any box (`sudo bash authelia.sh`, same pattern as `crowdsec.sh`) and
`asterisk-digital-ocean.sh` already auto-detects a local install (`if [ -d
"$DOCKER_DIR/authelia" ]`), switching from the remote-Authelia `forward_auth` flow to the
local `import authelia` snippet automatically — so a second, fully independent instance on
another machine (e.g. a droplet, for resilience if the first machine goes down) works with
no code changes. Use this instead of the same-instance approach above when the two domains
are on different machines, not just different domains on one machine.
The one real constraint for genuinely separate instances: Authelia's session cookie is
scoped to `AUTHELIA_DOMAIN` (the apex domain entered at install time) with
`includeSubDomains`-style matching, and the portal itself lives at `auth.${AUTHELIA_DOMAIN}`.
**Two independent instances must not share the same `AUTHELIA_DOMAIN`.** If they did, both
would try to claim the same `auth.<domain>` hostname (DNS can only point that at one
machine) and the same cookie scope with completely separate session stores — users bouncing
between subdomains fronted by different instances would see confusing repeated logins as
each instance's cookie gets overwritten/rejected by the other's. Give each instance either a
genuinely separate apex domain, or a distinct subdomain tree the other instance doesn't also
claim. (This constraint doesn't apply to the same-instance, multiple-domains approach above —
each domain there gets its own cookie entry by design, which is exactly what avoids the
collision.)
**Has built-in auth — no Authelia needed:**
`emby`, `jellyfin`, `audiobookshelf`, `immich`, `mealie`, `actualbudget`,
`homeassistant`, `portainer`, `meshcentral`, `traccar`, `uptimekuma`,
+141 -7
View File
@@ -206,13 +206,29 @@ install_authelia() {
# Don't clobber an existing install (it would regenerate secrets and break sessions).
if [ -f "$AUTHELIA_DIR/docker-compose.yml" ]; then
local RECONF=""
echo " ⚠ Authelia already exists at $AUTHELIA_DIR (secrets/users would be regenerated)."
prompt_yn " Reconfigure from scratch? (y/n):" "n" RECONF
if [ "$RECONF" != "y" ] && [ "$RECONF" != "Y" ]; then
echo " Keeping existing Authelia. (Edit config/users.yml then: cd $AUTHELIA_DIR && docker compose restart authelia)"
return 0
fi
echo " ⚠ Authelia already exists at $AUTHELIA_DIR."
echo ""
echo " 1) Add another protected domain to this instance (non-destructive —"
echo " one Authelia+Redis, multiple independent apex domains/logins)"
echo " 2) Reconfigure from scratch (regenerates secrets/users — breaks"
echo " existing sessions for every domain already on this instance)"
echo " 3) Leave as-is"
echo ""
local EXISTING_CHOICE=""
prompt_text " Choice [1/2/3]:" "3" EXISTING_CHOICE
case "$EXISTING_CHOICE" in
1)
add_authelia_domain
return 0
;;
2)
: # fall through to the full reinstall flow below
;;
*)
echo " Keeping existing Authelia. (Edit config/users.yml then: cd $AUTHELIA_DIR && docker compose restart authelia)"
return 0
;;
esac
fi
log_info "Installing Authelia..."
@@ -471,6 +487,16 @@ myservice.${AUTHELIA_DOMAIN} {
The \`(authelia)\` snippet and the \`auth.${AUTHELIA_DOMAIN}\` portal block were
added to \`$DOCKER_DIR/caddy/Caddyfile\` automatically.
## Protecting a second (or third) apex domain
Re-run this installer (\`sudo ./setup.sh authelia\` or \`sudo bash authelia.sh\`)
and choose **"Add another protected domain to this instance"** when it detects
the existing install. That domain gets its own \`session.cookies\` entry and its
own \`auth.<domain>\` portal — a separate login/session from ${AUTHELIA_DOMAIN},
so no accidental cross-domain SSO — but it's still one shared Authelia + Redis
container and one shared user database, not a second full stack. Cheaper than
standing up an entirely separate instance, and the right way to protect
multiple unrelated domains from the same box.
## Manage
\`\`\`
cd $AUTHELIA_DIR
@@ -510,5 +536,113 @@ README_MD
echo ""
}
# Adds a second (or third, etc.) independent apex domain to an EXISTING Authelia
# instance instead of standing up a whole separate Authelia+Redis stack for it.
# Authelia natively supports this: session.cookies and access_control.rules are
# both lists, so one instance can hold a distinct cookie scope + login portal per
# domain, each with its own session (no cross-domain SSO, but also no collision —
# see the "Running more than one Authelia instance" note in CLAUDE.md for why two
# domains can't just share one session.cookies entry). Far cheaper on RAM than a
# second full instance, which matters most on a small droplet.
add_authelia_domain() {
local AUTHELIA_DIR="$DOCKER_DIR/authelia"
local CONFIG_FILE="$AUTHELIA_DIR/config/configuration.yml"
local CADDY_FILE="$DOCKER_DIR/caddy/Caddyfile"
if [ ! -f "$CONFIG_FILE" ]; then
log_warning "No configuration.yml found at $CONFIG_FILE — install Authelia first."
return 1
fi
echo ""
echo " Add another apex domain to this Authelia instance."
echo " It gets its own session-cookie scope and its own auth.<domain> portal —"
echo " a separate login/session from your other domain(s) — but shares this"
echo " same Authelia + Redis container, not a second full stack."
echo ""
local NEW_DOMAIN=""
prompt_text " New domain (e.g., example.com):" "" NEW_DOMAIN
if [ -z "$NEW_DOMAIN" ]; then
log_warning "No domain entered — nothing to do."
return 0
fi
if grep -qF "\"*.${NEW_DOMAIN}\"" "$CONFIG_FILE" 2>/dev/null; then
log_warning "$NEW_DOMAIN is already configured in $CONFIG_FILE — nothing to do."
return 0
fi
# ── access_control.rules: insert right after "rules:" ────────────────────
awk -v domain="$NEW_DOMAIN" '
{ print }
/^ rules:$/ && !done {
print " - domain: \"*." domain "\""
print " policy: two_factor"
done=1
}
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
# ── session.cookies: insert right after "cookies:" ────────────────────────
awk -v domain="$NEW_DOMAIN" '
{ print }
/^ cookies:$/ && !done {
print " - domain: " domain
print " authelia_url: https://auth." domain
print " default_redirection_url: https://" domain
done=1
}
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
chown 1000:1000 "$CONFIG_FILE" 2>/dev/null || true
log_success "Added $NEW_DOMAIN to $CONFIG_FILE (access_control rule + session cookie scope)"
# ── Caddy portal block for the new domain ─────────────────────────────────
if [ -f "$CADDY_FILE" ]; then
if ! grep -q "^auth.${NEW_DOMAIN} {" "$CADDY_FILE"; then
cat >> "$CADDY_FILE" << CADDY_AUTH_BLOCK2
# ── Authelia login portal (${NEW_DOMAIN}) ─────────────────────────────────────
auth.${NEW_DOMAIN} {
# See auth.${AUTHELIA_DOMAIN:-<original domain>}'s block above for why
# header_up X-Forwarded-Host is required here, not optional.
reverse_proxy authelia:9091 {
header_up X-Forwarded-Host {http.request.header.X-Forwarded-Host}
}
log {
output file /var/log/caddy/auth.${NEW_DOMAIN}.log
}
}
CADDY_AUTH_BLOCK2
echo " ✓ Authelia portal block added for auth.${NEW_DOMAIN}"
docker ps --format '{{.Names}}' | grep -q "^caddy$" && \
{ docker exec -w /etc/caddy caddy caddy reload 2>/dev/null && echo " ✓ Caddy reloaded" || echo " ⚠ Reload manually: docker exec caddy caddy reload --config /etc/caddy/Caddyfile"; }
else
echo " ✓ auth.${NEW_DOMAIN} portal block already exists in the Caddyfile"
fi
else
echo " Caddy not installed — add an auth.${NEW_DOMAIN} portal block manually later (see README)."
fi
# ── Restart Authelia to pick up the new config ────────────────────────────
local RESTART_AUTH=""
prompt_yn " Restart Authelia to apply the new domain? (y/n):" "y" RESTART_AUTH
if [ "$RESTART_AUTH" = "y" ] || [ "$RESTART_AUTH" = "Y" ]; then
(cd "$AUTHELIA_DIR" && docker compose restart authelia 2>/dev/null) \
&& log_success "Authelia restarted" \
|| log_warning "Restart failed — check: docker compose logs authelia"
fi
echo ""
echo " Auth portal for $NEW_DOMAIN: https://auth.${NEW_DOMAIN}"
echo " Protect a service under this domain the same way as any other:"
echo " myservice.${NEW_DOMAIN} {"
echo " import authelia"
echo " reverse_proxy localhost:PORT"
echo " }"
echo " Same users/passwords work across every domain on this instance —"
echo " it's one shared user database, just separate sessions per domain."
echo ""
}
# Run immediately when executed directly (deferred until after function definition)
[[ "${_RUN_STANDALONE:-0}" == 1 ]] && install_authelia