Compare commits
3 Commits
0.1.0+0.1.
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d0448fa76 | |||
| bf8153f9db | |||
| a8cee2f92d |
15
.env.sample
15
.env.sample
@ -16,16 +16,21 @@ COMPOSE_FILE="compose.yml"
|
||||
# Extra domains for sites with custom domains (HostSNI backtick format)
|
||||
#EXTRA_DOMAINS=', `site1.example.com`, `site2.example.org`'
|
||||
|
||||
# Minimal image without atproto/git/shell (uncomment to use)
|
||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.min.yml"
|
||||
|
||||
# SSO/OIDC (uncomment to enable)
|
||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.oidc.yml"
|
||||
#SECRET_OIDC_ISSUER_URL_VERSION=v1 # generate=false
|
||||
#SECRET_OIDC_CLIENT_ID_VERSION=v1 # generate=false
|
||||
#SECRET_OIDC_CLIENT_SECRET_VERSION=v1 # generate=false
|
||||
#LICHEN_TOML_VERSION=v1
|
||||
|
||||
#OIDC_ISSUER_URL=https://keycloak.example.com/realms/myrealm
|
||||
#OIDC_CLIENT_ID=lichen
|
||||
#SECRET_OIDC_SECRET_VERSION=v1 # generate=false
|
||||
# Secrets
|
||||
SECRET_ADMIN_PASSWORD_VERSION=v1
|
||||
|
||||
# Config versions
|
||||
ENTRYPOINT_VERSION=v4
|
||||
CADDYFILE_VERSION=v2
|
||||
LICHEN_TOML_VERSION=v1
|
||||
|
||||
# Auth providers (comma-separated: file, atproto, oidc)
|
||||
#AUTH_PROVIDERS=file,atproto
|
||||
|
||||
77
README.md
77
README.md
@ -4,41 +4,74 @@
|
||||
|
||||
* **Category**: Apps
|
||||
* **Status**: 0
|
||||
* **Image**: ghcr.io/notplants/lichen-full
|
||||
* **Image**: [`notplants/lichen-full`](https://hub.docker.com/r/notplants/lichen-full)
|
||||
* **Healthcheck**: Yes
|
||||
* **Backups**: No
|
||||
* **Backups**: Yes
|
||||
* **Email**: No
|
||||
* **Tests**: No
|
||||
* **SSO**: No
|
||||
* **SSO**: Yes (OIDC)
|
||||
|
||||
<!-- endmetadata -->
|
||||
|
||||
## Quickstart
|
||||
## Basic usage
|
||||
|
||||
1. `abra app new lichen` (do **not** use `--secrets` yet, see below)
|
||||
2. `abra app deploy YOURAPPDOMAIN`
|
||||
1. Set up Docker Swarm and [`abra`]
|
||||
2. Deploy [`coop-cloud/traefik`]
|
||||
3. `abra app new lichen`
|
||||
4. `abra app config YOURAPPDOMAIN` — set `DOMAIN` to something that resolves to your Docker Swarm box
|
||||
5. `abra app secret generate YOURAPPDOMAIN --all`
|
||||
6. `abra app deploy YOURAPPDOMAIN`
|
||||
|
||||
## Auth providers
|
||||
|
||||
The `AUTH_PROVIDERS` env var controls which login methods are available (comma-separated). The default is `file,atproto`.
|
||||
|
||||
Valid providers: `file` (username/password), `atproto` (Bluesky), `oidc` (OpenID Connect).
|
||||
|
||||
## Minimal image
|
||||
|
||||
A lighter image without atproto/git/shell support is available. Enable it by uncommenting the min overlay in your app config:
|
||||
|
||||
```
|
||||
COMPOSE_FILE="$COMPOSE_FILE:compose.min.yml"
|
||||
```
|
||||
|
||||
When using the minimal image, set `AUTH_PROVIDERS=file` (or `file,oidc` with OIDC).
|
||||
|
||||
## SSO/OIDC
|
||||
|
||||
To enable OIDC login, uncomment the OIDC overlay and set your provider details in your app config:
|
||||
|
||||
```
|
||||
COMPOSE_FILE="$COMPOSE_FILE:compose.oidc.yml"
|
||||
OIDC_ISSUER_URL=https://keycloak.example.com/realms/myrealm
|
||||
OIDC_CLIENT_ID=lichen
|
||||
SECRET_OIDC_SECRET_VERSION=v1
|
||||
```
|
||||
|
||||
Then insert the client secret:
|
||||
|
||||
```
|
||||
abra app secret insert YOURAPPDOMAIN oidc_secret v1 YOUR_CLIENT_SECRET
|
||||
```
|
||||
|
||||
Add `oidc` to your `AUTH_PROVIDERS` (e.g. `AUTH_PROVIDERS=file,oidc`) and redeploy.
|
||||
|
||||
## TLS architecture (Caddy sidecar)
|
||||
|
||||
This recipe uses a **Caddy sidecar** for TLS instead of letting Traefik terminate
|
||||
TLS directly.
|
||||
This recipe uses a **Caddy sidecar** for TLS instead of letting Traefik terminate TLS directly.
|
||||
|
||||
The architecture:
|
||||
|
||||
1. **Traefik** receives TLS connections on port 443 and does **TCP passthrough**
|
||||
(no TLS termination) for traffic matching `DOMAIN` and `*.DOMAIN`, forwarding
|
||||
the raw TLS stream to Caddy.
|
||||
2. **Caddy** terminates TLS using **on-demand certificates** — it automatically
|
||||
obtains a Let's Encrypt certificate for each subdomain the first time a
|
||||
connection arrives, using the TLS-ALPN-01 challenge.
|
||||
1. **Traefik** receives TLS connections on port 443 and does **TCP passthrough** (no TLS termination) for traffic matching `DOMAIN` and `*.DOMAIN`, forwarding the raw TLS stream to Caddy.
|
||||
2. **Caddy** terminates TLS using **on-demand certificates** — it automatically obtains a Let's Encrypt certificate for each subdomain the first time a connection arrives.
|
||||
3. **Caddy** reverse proxies the decrypted HTTP traffic to lichen on port 9000.
|
||||
|
||||
**Note:** The first request to a new subdomain handle may take 10-30 seconds while
|
||||
Caddy obtains the TLS certificate from Let's Encrypt. Subsequent requests are instant.
|
||||
The first request to a new subdomain may take 10-30 seconds while Caddy obtains the TLS certificate. Subsequent requests are instant.
|
||||
|
||||
No changes to the Traefik recipe are needed — the TCP passthrough is configured
|
||||
entirely via deploy labels on the Caddy service in this recipe's `compose.yml`.
|
||||
No changes to the Traefik recipe are needed — the TCP passthrough is configured entirely via deploy labels in this recipe's `compose.yml`.
|
||||
|
||||
*
|
||||
---
|
||||
|
||||
recipe maintained by @notplants
|
||||
Recipe maintained by @notplants
|
||||
|
||||
[`abra`]: https://git.coopcloud.tech/coop-cloud/abra
|
||||
[`coop-cloud/traefik`]: https://git.coopcloud.tech/coop-cloud/traefik
|
||||
|
||||
6
compose.min.yml
Normal file
6
compose.min.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: notplants/lichen-min:0.1.9
|
||||
@ -3,28 +3,14 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
configs:
|
||||
- source: lichen_toml
|
||||
target: /data/lichen.toml
|
||||
mode: 0444
|
||||
environment:
|
||||
- OIDC_ENABLED=true
|
||||
- OIDC_ISSUER_URL=${OIDC_ISSUER_URL}
|
||||
- OIDC_CLIENT_ID=${OIDC_CLIENT_ID}
|
||||
secrets:
|
||||
- oidc_issuer_url
|
||||
- oidc_client_id
|
||||
- oidc_client_secret
|
||||
- oidc_secret
|
||||
|
||||
secrets:
|
||||
oidc_issuer_url:
|
||||
oidc_secret:
|
||||
external: true
|
||||
name: ${STACK_NAME}_oidc_issuer_url_${SECRET_OIDC_ISSUER_URL_VERSION}
|
||||
oidc_client_id:
|
||||
external: true
|
||||
name: ${STACK_NAME}_oidc_client_id_${SECRET_OIDC_CLIENT_ID_VERSION}
|
||||
oidc_client_secret:
|
||||
external: true
|
||||
name: ${STACK_NAME}_oidc_client_secret_${SECRET_OIDC_CLIENT_SECRET_VERSION}
|
||||
|
||||
configs:
|
||||
lichen_toml:
|
||||
name: ${STACK_NAME}_lichen_toml_${LICHEN_TOML_VERSION}
|
||||
file: lichen.toml.tmpl
|
||||
template_driver: golang
|
||||
name: ${STACK_NAME}_oidc_secret_${SECRET_OIDC_SECRET_VERSION}
|
||||
|
||||
12
compose.yml
12
compose.yml
@ -3,7 +3,7 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: notplants/lichen-full:0.1.6
|
||||
image: notplants/lichen-full:0.1.9
|
||||
entrypoint: ["/entrypoint.sh"]
|
||||
networks:
|
||||
- internal
|
||||
@ -13,11 +13,15 @@ services:
|
||||
- LM_USE_AUTH=true
|
||||
- LM_ROOT_DIR=/data
|
||||
- LM_PUBLIC_URL=https://${DOMAIN}
|
||||
- AUTH_PROVIDERS=${AUTH_PROVIDERS:-file,atproto}
|
||||
- RUST_LOG=${RUST_LOG:-info}
|
||||
configs:
|
||||
- source: entrypoint
|
||||
target: /entrypoint.sh
|
||||
mode: 0555
|
||||
- source: lichen_toml
|
||||
target: /data/lichen-base.toml
|
||||
mode: 0444
|
||||
secrets:
|
||||
- admin_password
|
||||
volumes:
|
||||
@ -28,7 +32,7 @@ services:
|
||||
max_attempts: 5
|
||||
labels:
|
||||
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-120}"
|
||||
- "coop-cloud.${STACK_NAME}.version=0.1.0+0.1.6"
|
||||
- "coop-cloud.${STACK_NAME}.version=0.1.2+v0.1.9"
|
||||
- "backupbot.backup=${ENABLE_BACKUPS:-true}"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9000/tls-check"]
|
||||
@ -83,3 +87,7 @@ configs:
|
||||
caddyfile:
|
||||
name: ${STACK_NAME}_caddyfile_${CADDYFILE_VERSION}
|
||||
file: Caddyfile
|
||||
lichen_toml:
|
||||
name: ${STACK_NAME}_lichen_toml_${LICHEN_TOML_VERSION}
|
||||
file: lichen.toml.tmpl
|
||||
template_driver: golang
|
||||
|
||||
@ -7,9 +7,18 @@ rm -f /usr/bin/bwrap
|
||||
# Install bash for lichen shell feature
|
||||
apk add --no-cache bash > /dev/null 2>&1 || true
|
||||
|
||||
# Set git identity for auto-commit
|
||||
git config --global user.email "lichen@${LM_DASHBOARD_DOMAIN:-localhost}"
|
||||
git config --global user.name "lichen"
|
||||
# Set git identity for auto-commit (git may not be present in min image)
|
||||
if command -v git > /dev/null 2>&1; then
|
||||
git config --global user.email "lichen@${LM_DASHBOARD_DOMAIN:-localhost}"
|
||||
git config --global user.name "lichen"
|
||||
fi
|
||||
|
||||
# Copy base config to lichen.toml only if user hasn't customized it
|
||||
if [ ! -f /data/lichen.toml ]; then
|
||||
# Convert comma-separated AUTH_PROVIDERS to TOML array
|
||||
TOML_PROVIDERS=$(echo "${AUTH_PROVIDERS:-file,atproto}" | sed 's/[^,][^,]*/\"&\"/g')
|
||||
{ echo "auth_providers = [$TOML_PROVIDERS]"; echo; cat /data/lichen-base.toml; } > /data/lichen.toml
|
||||
fi
|
||||
|
||||
ADMIN_PASSWORD=$(cat /run/secrets/admin_password)
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use_auth = true
|
||||
auth_providers = ["file", "oidc"]
|
||||
|
||||
{{ if env "OIDC_ENABLED" }}
|
||||
[oidc]
|
||||
issuer_url = "{{ secret "oidc_issuer_url" }}"
|
||||
client_id = "{{ secret "oidc_client_id" }}"
|
||||
client_secret = "{{ secret "oidc_client_secret" }}"
|
||||
issuer_url = "{{ env "OIDC_ISSUER_URL" }}"
|
||||
client_id = "{{ env "OIDC_CLIENT_ID" }}"
|
||||
client_secret = "{{ secret "oidc_secret" }}"
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user