update: quick install

This commit is contained in:
Nathan FONTEYNE 2026-07-08 13:09:46 +02:00
parent 0300f7fef0
commit 0683108c8e
3 changed files with 156 additions and 30 deletions

View file

@ -14,12 +14,19 @@ SESSION_SECRET=change-me-to-a-long-random-string
DEV_BYPASS_AUTH=false DEV_BYPASS_AUTH=false
# Authentik OIDC (not needed if DEV_BYPASS_AUTH=true) # Authentik OIDC (not needed if DEV_BYPASS_AUTH=true)
AUTHENTIK_ISSUER_URL=https://auth.example.com/application/o/octane-website/ # Prefer Authentik's internal container name/port over traefik-proxy (avoids a
# round trip through Traefik); falls back to the public URL if you don't know it.
AUTHENTIK_ISSUER_URL=http://authentik-server:9000/application/o/octane-website/
OIDC_CLIENT_ID= OIDC_CLIENT_ID=
OIDC_CLIENT_SECRET= OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URI=https://octane.example.com/auth/callback OIDC_REDIRECT_URI=https://octane.dandrove.com/auth/callback
ADMIN_GROUP_NAME=octane-admins ADMIN_GROUP_NAME=octane-admins
# Docker networking (must match the network created by your existing Authentik compose stack) # Docker networking: external network shared with Traefik and Authentik
AUTHENTIK_NETWORK_NAME=authentik_default TRAEFIK_NETWORK_NAME=traefik-proxy
# Public hostname Traefik routes to this app (used in docker-compose.yml labels)
APP_DOMAIN=octane.dandrove.com
# Only used by docker-compose.dev.yml (local testing without Traefik)
APP_PORT=3000 APP_PORT=3000

152
README.md
View file

@ -4,6 +4,127 @@ Application interne pour le groupe : répertoire de morceaux travaillés (avec l
Stack 100% JavaScript : backend Node.js/Express servant des pages HTML/CSS/JS vanilla (pas de framework front, pas de build step) + API REST, PostgreSQL, authentification via OpenID Connect contre une instance Authentik existante. Stack 100% JavaScript : backend Node.js/Express servant des pages HTML/CSS/JS vanilla (pas de framework front, pas de build step) + API REST, PostgreSQL, authentification via OpenID Connect contre une instance Authentik existante.
## Démarrage rapide (serveur avec Traefik)
Ce qui suit correspond au déploiement réel : Traefik en reverse proxy, Authentik sur le même réseau Docker externe `traefik-proxy`, l'app exposée sur `octane.dandrove.com`, l'image tirée de `ghcr.io` (voir [CI/CD](#cicd-et-mises-à-jour)).
```bash
git clone https://github.com/nfonteyne/octane-website.git
cd octane-website
cp .env.example .env
```
Éditer `.env` (au minimum) :
```
DATABASE_URL=postgres://octane:changeme@postgres:5432/octane
POSTGRES_PASSWORD=changeme
SESSION_SECRET=une-longue-chaine-aleatoire
AUTHENTIK_ISSUER_URL=http://authentik-server:9000/application/o/octane-website/
OIDC_CLIENT_ID=...
OIDC_CLIENT_SECRET=...
OIDC_REDIRECT_URI=https://octane.dandrove.com/auth/callback
ADMIN_GROUP_NAME=octane-admins
TRAEFIK_NETWORK_NAME=traefik-proxy
APP_DOMAIN=octane.dandrove.com
```
`AUTHENTIK_ISSUER_URL` utilise ici le nom du conteneur Authentik sur le réseau `traefik-proxy` (remplacez `authentik-server` par le vrai nom de service de votre stack Authentik — `docker ps` sur cette stack vous le donnera) plutôt que l'URL publique, pour éviter un aller-retour inutile par Traefik. L'URL publique fonctionne aussi si vous préférez.
Si le réseau `traefik-proxy` n'existe pas encore (il devrait déjà exister si Authentik tourne dessus) :
```bash
docker network create traefik-proxy
```
Puis démarrer :
```bash
docker compose pull
docker compose up -d
```
`docker-compose.yml` (à la racine du repo) est déjà prêt pour ce cas précis :
```yaml
services:
app:
image: ${APP_IMAGE:-ghcr.io/nfonteyne/octane-website:latest}
container_name: octane-app
restart: unless-stopped
env_file: .env
depends_on:
- postgres
networks:
- default
- traefik-proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik-proxy"
- "traefik.http.routers.octane.rule=Host(`${APP_DOMAIN:-octane.dandrove.com}`)"
- "traefik.http.routers.octane.entrypoints=websecure"
- "traefik.http.routers.octane.tls.certresolver=myresolver"
- "traefik.http.services.octane.loadbalancer.server.port=3000"
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: octane
POSTGRES_USER: octane
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- default
networks:
default:
traefik-proxy:
external: true
name: ${TRAEFIK_NETWORK_NAME:-traefik-proxy}
volumes:
pgdata:
```
Pas de port publié sur l'hôte : Traefik parle directement au conteneur `octane-app` sur le réseau `traefik-proxy`, port 3000 (celui écouté par Express en interne).
## Intégration Traefik
Le `docker-compose.yml` ci-dessus utilise déjà les **labels Docker** (option recommandée). Deux cas selon la configuration de votre Traefik :
### Option A — provider Docker (labels), déjà en place
Si Traefik tourne avec le provider Docker activé (`--providers.docker=true` et accès au socket Docker) et surveille le réseau `traefik-proxy`, rien à faire de plus : les labels du service `app` suffisent. Vérifiez juste que :
- Traefik est bien attaché au réseau `traefik-proxy`,
- l'entrypoint `websecure` et le `certResolver` `myresolver` correspondent aux noms utilisés dans votre configuration Traefik (adaptez les labels sinon).
### Option B — provider fichier (dynamic config)
Si votre Traefik est plutôt piloté par des fichiers de configuration dynamique (comme votre exemple `guitar-scale`), retirez les `labels` du service `app` dans `docker-compose.yml` et ajoutez ce fichier à votre dossier de conf dynamique Traefik (ex: `dynamic/octane.yml`) :
```yaml
http:
routers:
octane:
entryPoints: ["websecure"]
rule: Host(`octane.dandrove.com`)
service: octane-service
tls:
certResolver: myresolver
services:
octane-service:
loadBalancer:
servers:
- url: "http://octane-app:3000"
```
`octane-app` est le `container_name` fixé dans `docker-compose.yml` — Docker en fait un nom résolvable en DNS pour tout conteneur attaché au même réseau (`traefik-proxy`), donc Traefik peut l'atteindre directement par ce nom sans passer par le provider Docker.
## Architecture ## Architecture
```mermaid ```mermaid
@ -116,44 +237,33 @@ Le rôle admin est déterminé par un claim `groups` renvoyé par Authentik (voi
## Prérequis ## Prérequis
- Docker + Docker Compose - Docker + Docker Compose
- Une instance Authentik déjà en place, avec un réseau Docker accessible depuis ce projet - Une instance Authentik déjà en place
- Un reverse proxy Traefik déjà en place, avec un réseau Docker externe partagé (`traefik-proxy` dans nos exemples) sur lequel Authentik est également connecté
## Configuration Authentik ## Configuration Authentik
1. Créer un **Provider** OAuth2/OIDC dans Authentik, avec comme redirect URI la valeur que vous mettrez dans `OIDC_REDIRECT_URI` (ex: `https://octane.example.com/auth/callback`). 1. Créer un **Provider** OAuth2/OIDC dans Authentik, avec comme redirect URI la valeur que vous mettrez dans `OIDC_REDIRECT_URI` (ex: `https://octane.dandrove.com/auth/callback`).
2. Créer une **Application** Authentik pointant vers ce provider. 2. Créer une **Application** Authentik pointant vers ce provider.
3. S'assurer qu'un **scope mapping** expose un claim `groups` dans l'ID token (Authentik a un mapping `groups` intégré dans les versions récentes, sinon créer un mapping personnalisé renvoyant `request.user.ak_groups.all()`). 3. S'assurer qu'un **scope mapping** expose un claim `groups` dans l'ID token (Authentik a un mapping `groups` intégré dans les versions récentes, sinon créer un mapping personnalisé renvoyant `request.user.ak_groups.all()`).
4. Créer un **groupe** Authentik (ex: `octane-admins`) et y ajouter les membres qui doivent être admins de l'application. 4. Créer un **groupe** Authentik (ex: `octane-admins`) et y ajouter les membres qui doivent être admins de l'application.
5. Noter le Client ID / Client Secret du provider. 5. Noter le Client ID / Client Secret du provider.
## Installation ## Variables d'environnement (référence complète)
```bash Le [Démarrage rapide](#démarrage-rapide-serveur-avec-traefik) ci-dessus couvre le cas concret. Référence complète des variables de `.env` :
cp .env.example .env
```
Remplir `.env` :
| Variable | Description | | Variable | Description |
|---|---| |---|---|
| `DATABASE_URL` | Chaîne de connexion Postgres (déjà cohérente avec le service `postgres` du compose) | | `DATABASE_URL` | Chaîne de connexion Postgres (déjà cohérente avec le service `postgres` du compose) |
| `POSTGRES_PASSWORD` | Mot de passe du service Postgres | | `POSTGRES_PASSWORD` | Mot de passe du service Postgres |
| `SESSION_SECRET` | Chaîne aléatoire longue pour signer les cookies de session | | `SESSION_SECRET` | Chaîne aléatoire longue pour signer les cookies de session |
| `AUTHENTIK_ISSUER_URL` | URL d'issuer OIDC de l'application Authentik (ex: `https://auth.example.com/application/o/octane-website/`) | | `AUTHENTIK_ISSUER_URL` | URL d'issuer OIDC de l'application Authentik (interne, ex: `http://authentik-server:9000/application/o/octane-website/`, ou publique) |
| `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` | Identifiants du provider Authentik | | `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` | Identifiants du provider Authentik |
| `OIDC_REDIRECT_URI` | URL publique de callback, doit correspondre à celle configurée dans Authentik | | `OIDC_REDIRECT_URI` | URL publique de callback, doit correspondre à celle configurée dans Authentik (ex: `https://octane.dandrove.com/auth/callback`) |
| `ADMIN_GROUP_NAME` | Nom du groupe Authentik dont les membres deviennent admins | | `ADMIN_GROUP_NAME` | Nom du groupe Authentik dont les membres deviennent admins |
| `AUTHENTIK_NETWORK_NAME` | Nom du réseau Docker de votre stack Authentik existante (vérifier avec `docker network ls`) | | `TRAEFIK_NETWORK_NAME` | Nom du réseau Docker externe partagé avec Traefik et Authentik (défaut `traefik-proxy`) |
| `APP_PORT` | Port exposé sur l'hôte (défaut `3000`) | | `APP_DOMAIN` | Nom de domaine public utilisé par Traefik pour router vers l'app (ex: `octane.dandrove.com`) |
| `APP_PORT` | Port hôte utilisé uniquement par `docker-compose.dev.yml` (test local sans Traefik) |
Puis démarrer :
```bash
docker compose pull
docker compose up -d
```
`docker-compose.yml` référence l'image publiée par la CI (`ghcr.io/nfonteyne/octane-website:latest`, voir [CI/CD](#cicd-et-mises-à-jour) ci-dessous) plutôt que de la construire localement — c'est ce fichier que vous utilisez sur votre serveur.
Les migrations SQL (`src/db/migrations/*.sql`) sont exécutées automatiquement au démarrage du conteneur `app`, de façon idempotente (une table `schema_migrations` garde la trace des fichiers déjà appliqués). Les migrations SQL (`src/db/migrations/*.sql`) sont exécutées automatiquement au démarrage du conteneur `app`, de façon idempotente (une table `schema_migrations` garde la trace des fichiers déjà appliqués).

View file

@ -3,15 +3,24 @@ services:
# Built and pushed by .github/workflows/ci.yml on every push to main. # Built and pushed by .github/workflows/ci.yml on every push to main.
# Watchtower on the server picks up new digests on this tag automatically. # Watchtower on the server picks up new digests on this tag automatically.
image: ${APP_IMAGE:-ghcr.io/nfonteyne/octane-website:latest} image: ${APP_IMAGE:-ghcr.io/nfonteyne/octane-website:latest}
container_name: octane-app
restart: unless-stopped restart: unless-stopped
env_file: .env env_file: .env
ports:
- "${APP_PORT:-3000}:3000"
depends_on: depends_on:
- postgres - postgres
networks: networks:
- default - default
- authentik - traefik-proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik-proxy"
- "traefik.http.routers.octane.rule=Host(`${APP_DOMAIN:-octane.dandrove.com}`)"
- "traefik.http.routers.octane.entrypoints=websecure"
- "traefik.http.routers.octane.tls.certresolver=myresolver"
- "traefik.http.services.octane.loadbalancer.server.port=3000"
# No host port published: Traefik reaches the container directly over
# traefik-proxy. Add "ports: ['3000:3000']" temporarily if you need
# to hit the app straight from the host while debugging.
postgres: postgres:
image: postgres:16-alpine image: postgres:16-alpine
@ -27,9 +36,9 @@ services:
networks: networks:
default: default:
authentik: traefik-proxy:
external: true external: true
name: ${AUTHENTIK_NETWORK_NAME:-authentik_default} name: ${TRAEFIK_NETWORK_NAME:-traefik-proxy}
volumes: volumes:
pgdata: pgdata: