Constellation compile des fiches de célébrités à partir de plusieurs sources : Wikipedia, Wikidata, API Ninjas et Google Knowledge Graph. Chaque fiche a une galerie photo, une filmographie avec le casting et une discographie. Une page d'accueil montre le graphe des liens entre célébrités, par les films et séries qu'elles ont en commun.
L'image contient l'application complète, front Angular et API Symfony, servie par FrankenPHP sur le
port 8080. Il suffit d'y ajouter PostgreSQL ; le docker-compose.yml ci-dessous fournit tout.
| Tag | Contenu |
|---|---|
1.1.0, latest | Version actuelle |
1.0.0 | Première version |
Plateforme : linux/amd64.
mkdir constellation && cd constellation
docker-compose.ymlDeux variantes : choisissez celle qui correspond à votre serveur.
Caddy obtient et renouvelle le certificat Let's Encrypt. C'est la seule porte d'entrée du serveur.
name: constellation
x-app: &app
image: docker.io/iemperor/constellation:${CONSTELLATION_VERSION:-1.1.0}
restart: unless-stopped
read_only: true
tmpfs:
- /tmp
- /config:uid=1000,gid=1000,mode=0700
security_opt:
- no-new-privileges:true
cap_drop: [ALL]
environment: &app-env
FRONTEND_URL: https://${DOMAIN:?DOMAIN manquant}
APP_SECRET: ${APP_SECRET:?APP_SECRET manquant}
JWT_PASSPHRASE: ${JWT_PASSPHRASE:?JWT_PASSPHRASE manquant}
SETTINGS_ENCRYPTION_KEY: ${SETTINGS_ENCRYPTION_KEY:?SETTINGS_ENCRYPTION_KEY manquant}
DATABASE_URL: postgresql://constellation:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD manquant}@db:5432/constellation?serverVersion=17&charset=utf8
MAILER_DSN: ${MAILER_DSN:-null://null}
MAILER_FROM: ${MAILER_FROM:-}
SOURCES_CONTACT: ${SOURCES_CONTACT:-}
API_NINJAS_KEY: ${API_NINJAS_KEY:-}
GOOGLE_KG_API_KEY: ${GOOGLE_KG_API_KEY:-}
TMDB_API_READ_ACCESS_TOKEN: ${TMDB_API_READ_ACCESS_TOKEN:-}
TMDB_API_KEY: ${TMDB_API_KEY:-}
IMMICH_URL: ${IMMICH_URL:-}
IMMICH_API_KEY: ${IMMICH_API_KEY:-}
WIKIPEDIA_LANG: ${WIKIPEDIA_LANG:-fr}
TMDB_LANGUAGE: ${TMDB_LANGUAGE:-fr-FR}
volumes:
- app-data:/data
- app-var:/app/var
- photos:/app/public/media/photos
networks: [web, data]
services:
# Reverse proxy HTTPS (Let's Encrypt) : sa configuration est écrite au démarrage
proxy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
environment:
DOMAIN: ${DOMAIN}
entrypoint: ["/bin/sh", "-c"]
command:
- |
cat > /etc/caddy/Caddyfile <<'CADDYFILE'
{$$DOMAIN} {
encode zstd gzip
header Strict-Transport-Security "max-age=31536000; includeSubDomains"
reverse_proxy app:8080 {
transport http {
read_timeout 120s
}
}
}
CADDYFILE
exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
volumes:
- proxy-data:/data
- proxy-config:/config
security_opt:
- no-new-privileges:true
networks: [web]
depends_on:
app:
condition: service_healthy
# Front Angular + API Symfony
app:
<<: *app
depends_on:
db:
condition: service_healthy
# Tâches quotidiennes : rafraîchissement TMDB, synchronisation Immich
scheduler:
<<: *app
command: ["constellation-scheduler"]
healthcheck:
disable: true
environment:
<<: *app-env
CONSTELLATION_INIT: "0"
SCHEDULER_INTERVAL: ${SCHEDULER_INTERVAL:-86400}
IMMICH_AUTO_LINK: ${IMMICH_AUTO_LINK:-0}
depends_on:
app:
condition: service_healthy
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_DB: constellation
POSTGRES_USER: constellation
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U constellation -d constellation"]
interval: 10s
timeout: 5s
retries: 10
security_opt:
- no-new-privileges:true
networks: [data]
networks:
web: {}
# Sans accès extérieur : la base n'est joignable que par l'application
data:
internal: true
volumes:
app-data: {}
app-var: {}
photos: {}
db-data: {}
proxy-data: {}
proxy-config: {}
Reprenez la variante A, puis :
proxy et les volumes proxy-data et proxy-config.app :
app:
<<: *app
ports:
- "127.0.0.1:8080:8080" # 0.0.0.0:8080:8080 si le proxy tourne sur une autre machine
depends_on:
db:
condition: service_healthy
FRONTEND_URL: https://${DOMAIN:?DOMAIN manquant} par l'adresse publique complète du site, par
exemple FRONTEND_URL: https://constellation.mon-domaine.fr.http://<ip-du-serveur>:8080. Le proxy doit remplacer
l'en-tête X-Forwarded-For par l'IP du visiteur, comme le fait Nginx Proxy Manager par défaut. L'application s'en
sert pour limiter les tentatives de connexion.Test sur le réseau local, sans HTTPS :
FRONTEND_URL: http://<ip-du-serveur>:8080, et ajoutezCOOKIE_SECURE: "0"à l'environnement. Sinon, le navigateur refuse le cookie de session. N'exposez jamais ce mode sur internet.
.envcat > .env <<'EOF'
# Nom de domaine du site (doit pointer vers ce serveur)
DOMAIN=constellation.mon-domaine.fr
CONSTELLATION_VERSION=1.1.0
# Secrets (générés à l'étape suivante)
APP_SECRET=
JWT_PASSPHRASE=
SETTINGS_ENCRYPTION_KEY=
POSTGRES_PASSWORD=
# Email ou URL transmis à Wikimedia et MusicBrainz (exigé par leurs règles d'usage)
SOURCES_CONTACT=
# Serveur mail (modifiable ensuite dans l'administration)
# ex. smtp://utilisateur:[email protected]:587
MAILER_DSN=null://null
MAILER_FROM=
# Clés des sources : facultatives ici, saisissables dans l'administration
API_NINJAS_KEY=
GOOGLE_KG_API_KEY=
TMDB_API_READ_ACCESS_TOKEN=
TMDB_API_KEY=
IMMICH_URL=
IMMICH_API_KEY=
EOF
chmod 600 .env
sed -i "s|^APP_SECRET=.*|APP_SECRET=$(openssl rand -hex 32)|; s|^JWT_PASSPHRASE=.*|JWT_PASSPHRASE=$(openssl rand -hex 32)|; s|^SETTINGS_ENCRYPTION_KEY=.*|SETTINGS_ENCRYPTION_KEY=$(openssl rand -hex 32)|; s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 24)|" .env
Ouvrez ensuite .env et renseignez DOMAIN et SOURCES_CONTACT.
Sauvegardez
.env.SETTINGS_ENCRYPTION_KEYchiffre les clés d'API et le mot de passe SMTP saisis dans l'administration : sans elle, ils deviennent illisibles. Ne changez pasPOSTGRES_PASSWORDaprès le premier démarrage, car la base est créée avec ce mot de passe.
docker compose up -d
docker compose ps
Le service app doit être healthy, généralement en moins d'une minute. Au premier démarrage, l'application vérifie
sa configuration, attend la base, crée les tables et génère ses clés JWT.
docker compose exec app bin/console app:create-admin [email protected]
Le mot de passe est demandé de façon masquée, avec 12 caractères au minimum.
Ouvrez https://<votre-domaine>, connectez-vous, puis allez dans Administration › Paramètres :
| Source | Utilité | Où obtenir la clé |
|---|---|---|
| TMDB | Filmographies, casting | themoviedb.org › Paramètres › API (« API Read Access Token ») |
| API Ninjas | Taille, fortune, naissance | api-ninjas.com › Profil |
| Google Knowledge Graph | Descriptions, images | Google Cloud › API « Knowledge Graph Search » |
| Immich | Albums photo | Immich › Paramètres du compte › Clés d'API (permissions album.read, asset.read, asset.view, et album.create pour créer des albums) |
Wikipedia, Wikidata, Wikimedia Commons, Openverse et MusicBrainz ne demandent pas de clé.
# Dans .env : CONSTELLATION_VERSION=<nouvelle version>
docker compose pull
docker compose up -d
Les migrations de base sont appliquées automatiquement au démarrage. Faites une sauvegarde avant chaque mise à jour.
# Base de données
docker compose exec -T db pg_dump -U constellation -Fc constellation > constellation-$(date +%F).dump
# Photos
docker run --rm -v constellation_photos:/photos:ro -v "$PWD":/backup alpine tar czf /backup/photos-$(date +%F).tgz -C /photos .
Restauration de la base :
docker compose exec -T db pg_restore -U constellation -d constellation --clean --if-exists < constellation-AAAA-MM-JJ.dump
| Volume | Contenu | À sauvegarder |
|---|---|---|
db-data | Base PostgreSQL | Oui, avec pg_dump |
photos | Photos des galeries | Oui |
app-data | Clés JWT, données Caddy | Facultatif |
app-var | Cache, verrous | Non |
Le service scheduler lance, 5 minutes après le démarrage puis une fois par jour :
app:tmdb:refresh : rafraîchit les filmographies. Les conditions TMDB interdisent de garder leurs données plus
de 6 mois.app:immich:sync : synchronise les galeries avec les albums Immich.Avec IMMICH_AUTO_LINK=1, chaque fiche sans album est d'abord liée à l'album Immich de même nom.
docker compose logs -f app # journaux (JSON)
docker compose exec app bin/console app:create-admin email # créer ou promouvoir un administrateur
docker compose exec scheduler bin/console app:immich:sync --auto-link
docker compose exec db psql -U constellation constellation # console SQL
| Variable | Obligatoire | Rôle |
|---|---|---|
DOMAIN | oui (variante A) | Nom de domaine ; l'adresse du site devient https://DOMAIN |
FRONTEND_URL | oui (variante B) | Adresse publique du site |
APP_SECRET | oui | Secret Symfony (openssl rand -hex 32) |
JWT_PASSPHRASE | oui | Protège la clé privée JWT |
SETTINGS_ENCRYPTION_KEY | oui | 64 caractères hexadécimaux (openssl rand -hex 32) |
POSTGRES_PASSWORD | oui | Mot de passe de la base |
SOURCES_CONTACT | conseillé | Email ou URL transmis à Wikimedia et MusicBrainz |
MAILER_DSN / MAILER_FROM | non | Serveur SMTP et expéditeur (aussi dans l'administration) |
TMDB_API_READ_ACCESS_TOKEN, TMDB_API_KEY, API_NINJAS_KEY, GOOGLE_KG_API_KEY, IMMICH_URL, IMMICH_API_KEY | non | Clés des sources (aussi dans l'administration) |
WIKIPEDIA_LANG / TMDB_LANGUAGE | non | fr / fr-FR par défaut |
COOKIE_SECURE | non | 1 par défaut ; 0 uniquement pour un test local en HTTP |
SCHEDULER_INTERVAL | non | Intervalle des tâches périodiques, en secondes (86400) |
IMMICH_AUTO_LINK | non | 1 : lie automatiquement les albums Immich de même nom |
no-new-privileges.X-Frame-Options: DENY, nosniff,
Referrer-Policy et Permissions-Policy. Les photos sont servies avec sandbox.HttpOnly, Secure et
SameSite=Strict. Les tentatives de connexion, d'inscription et d'email sont limitées.| Symptôme | Cause probable |
|---|---|
la variable … est obligatoire dans les journaux | Variable absente de .env |
base de données injoignable | POSTGRES_PASSWORD modifié après le premier démarrage. Remettez l'ancien, ou supprimez le volume constellation_db-data si la base est vide |
app reste unhealthy | Consultez docker compose logs app. Vérifiez aussi l'architecture : l'image est amd64 |
| Déconnexion juste après la connexion | Site servi en HTTP avec COOKIE_SECURE=1 |
| Aucun email reçu | Serveur mail non configuré (MAILER_DSN=null://null) |
| « Trop de tentatives » pour tout le monde | Le proxy ne transmet pas l'IP du visiteur (X-Forwarded-For) |
| Certificat HTTPS non obtenu (variante A) | Le domaine ne pointe pas vers le serveur, ou les ports 80 et 443 sont fermés |
Les données de filmographie viennent de l'API TMDB, sans être approuvées ni certifiées par TMDB : leur usage est réservé à un cadre non commercial. Les données MusicBrainz et Wikidata sont sous licence CC0. Les photos Commons et Openverse sont affichées avec leur auteur et leur licence. Les photos importées depuis Immich doivent être des photos que vous avez le droit de diffuser.
Content type
Image
Digest
sha256:fcfec38f9…
Size
129.2 MB
Last updated
22 days ago
docker pull iemperor/constellation