diff --git a/.env.example b/.env.example index 320c2ed..1f6a36f 100644 --- a/.env.example +++ b/.env.example @@ -40,21 +40,14 @@ NODE_ENV=production PORT=3000 # ---- VPS sans reverse proxy existant (voir README) ---- -# Choisissez UNE surcouche via COMPOSE_FILE. -# -# Phase 1, sans nom de domaine : HTTP simple sur le port 80 (http://IP). -#COMPOSE_FILE=docker-compose.yml:docker-compose.http.yml -# -# Phase 2, DNS en place : Caddy en 80/443, certificat Let's Encrypt automatique. -# SITE_DOMAIN et CADDY_EMAIL ne sont lus que par cette surcouche. +# Caddy devant l'application : ports 80 et 443, certificat Let's Encrypt +# automatique pour SITE_DOMAIN, et réponse immédiate sur http://IP_DU_SERVEUR +# tant que le DNS n'est pas configuré. Renseignez SITE_DOMAIN même si le +# domaine ne pointe pas encore : la bascule en HTTPS se fera toute seule. #COMPOSE_FILE=docker-compose.yml:docker-compose.caddy.yml #SITE_DOMAIN=pleinr.example.fr #CADDY_EMAIL=vous@example.fr -# URL publique du site. Se règle normalement dans Backend › Réseaux sociaux ; -# cette variable ne sert que de repli (puis AUTH_URL en dernier recours). -NEXT_PUBLIC_SITE_URL= - # ---- Publication des promotions sur les réseaux sociaux ---- # La configuration se fait désormais dans Backend › Réseaux sociaux : on y colle # les identifiants de l'application, on clique Connecter, et les jetons sont diff --git a/Caddyfile b/Caddyfile index 6a9e2bd..0b7ba57 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,6 +1,19 @@ # Reverse proxy Caddy pour Plein R (voir docker-compose.caddy.yml). -# Caddy gère seul le certificat Let's Encrypt et la redirection HTTP -> HTTPS. - +# +# Deux entrées, pour que l'installation soit utilisable AVANT que le DNS ne +# soit configuré, et bascule toute seule ensuite : +# +# 1. {$SITE_DOMAIN} — le nom de domaine. Caddy obtient et renouvelle seul le +# certificat Let's Encrypt et redirige HTTP vers HTTPS. Tant que le DNS ne +# pointe pas sur le serveur, la demande de certificat échoue et Caddy +# réessaie en arrière-plan, avec un délai croissant : rien à relancer, le +# site devient joignable en HTTPS peu après la mise en place du DNS. +# +# 2. http:// — fourre-tout HTTP, qui répond notamment sur http://IP_DU_SERVEUR. +# Le préfixe http:// désactive explicitement le HTTPS automatique pour ce +# bloc (aucun certificat n'existe pour une IP nue). Le bloc du domaine étant +# plus spécifique, il reste prioritaire, et la redirection HTTP vers HTTPS +# du domaine est insérée avant ce fourre-tout. { email {$CADDY_EMAIL} } @@ -9,3 +22,8 @@ encode zstd gzip reverse_proxy pleinr-app:3000 } + +http:// { + encode zstd gzip + reverse_proxy pleinr-app:3000 +} diff --git a/README.md b/README.md index f9c4084..bb3635c 100644 --- a/README.md +++ b/README.md @@ -48,51 +48,25 @@ charge des données de démonstration. Ensuite : ## Installation sur un VPS sans reverse proxy Le `docker-compose.yml` suppose un Nginx Proxy Manager déjà en place (réseau -externe `nginx_default`). Sur un serveur nu, deux surcouches couvrent les deux -situations, sans jamais modifier le fichier de base : +externe `nginx_default`). Sur un serveur nu, `docker-compose.caddy.yml` ajoute +**Caddy** devant l'application, sans modifier le fichier de base. -| Surcouche | Sert sur | Pré-requis | +Caddy sert deux entrées à la fois (voir `Caddyfile`) : + +| Adresse | Sert | Certificat | |---|---|---| -| `docker-compose.http.yml` | `http://IP_DU_SERVEUR` (port 80) | aucun | -| `docker-compose.caddy.yml` | `https://votre-domaine.fr` (80 + 443) | DNS pointé sur le serveur | +| `http://IP_DU_SERVEUR` | tout de suite | aucun (impossible sur une IP nue) | +| `https://votre-domaine.fr` | dès que le DNS pointe sur le serveur | Let's Encrypt, automatique | -On choisit l'une ou l'autre avec la variable `COMPOSE_FILE` du `.env`. Passer -de la première à la seconde ne demande que de changer cette ligne : les données, -le compte administrateur et le secret de session vivent dans des volumes Docker -et sont conservés. - -### Phase 1 — valider l'installation sans domaine (HTTP, port 80) +On installe donc **tout d'un coup**, on valide par l'IP, et la bascule en HTTPS +se fait ensuite d'elle-même : il n'y a **rien à relancer** au moment de +configurer le DNS. Tant que le domaine ne résout pas, Caddy réessaie la demande +de certificat en arrière-plan avec un délai croissant. 1. Installer Docker : `curl -fsSL https://get.docker.com | sh` -2. Cloner le dépôt, copier `.env.example` en `.env` et renseigner au minimum - `POSTGRES_PASSWORD`, `DATABASE_URL` et `SEED_ADMIN_EMAIL`, puis ajouter : - - ```dotenv - COMPOSE_FILE=docker-compose.yml:docker-compose.http.yml - ``` - - Laisser `AUTH_URL` **vide** : Auth.js déduit alors l'URL des en-têtes de la - requête, ce qui évite de la corriger à la phase 2. -3. Ouvrir le port : `sudo ufw allow 80/tcp` -4. Lancer : `docker compose up -d --build` -5. Relever le mot de passe administrateur, affiché une seule fois : - `docker logs pleinr-app 2>&1 | grep -i -A2 "mot de passe"` - -Le site répond sur `http://IP_DU_SERVEUR`. En HTTP sur une IP, la directive -`upgrade-insecure-requests` de la CSP peut empêcher le navigateur de charger -styles et scripts ; pour une vérification fidèle, passer par un tunnel SSH -(`ssh -L 8080:localhost:80 utilisateur@IP`) et ouvrir `http://localhost:8080`. - -### Phase 2 — passer en HTTPS sur le nom de domaine - -`docker-compose.caddy.yml` ajoute **Caddy** devant l'application : il écoute en -80 et 443, obtient et renouvelle seul le certificat Let's Encrypt et redirige -HTTP vers HTTPS. Une fois l'enregistrement DNS A du domaine pointé sur le -serveur : - -1. Ouvrir le port 443 : `sudo ufw allow 443/tcp` -2. Arrêter la pile de la phase 1 : `docker compose down` -3. Dans `.env`, remplacer la surcouche et déclarer le domaine : +2. Ouvrir les ports : `sudo ufw allow 80,443/tcp` +3. Cloner le dépôt, copier `.env.example` en `.env` et renseigner au minimum + `POSTGRES_PASSWORD`, `DATABASE_URL`, `SEED_ADMIN_EMAIL`, puis : ```dotenv COMPOSE_FILE=docker-compose.yml:docker-compose.caddy.yml @@ -100,14 +74,27 @@ serveur : CADDY_EMAIL=vous@example.fr ``` -4. Relancer : `docker compose up -d --build` + Renseigner `SITE_DOMAIN` **même si le DNS n'est pas encore en place** : c'est + ce qui rend la bascule automatique. Laisser `AUTH_URL` **vide** : Auth.js + déduit alors l'URL des en-têtes de la requête, et suit donc l'IP puis le + domaine sans reconfiguration. +4. Lancer : `docker compose up -d --build` +5. Relever le mot de passe administrateur, affiché une seule fois : + `docker logs pleinr-app 2>&1 | grep -i -A2 "mot de passe"` -Le site est alors servi sur `https://votre-domaine.fr`. Aucun port applicatif -n'est plus publié : tout passe par Caddy. Les certificats vivent dans le volume -`caddy_data` et se renouvellent seuls. Vérification : +Aucun port applicatif n'est publié : tout passe par Caddy. Les certificats +vivent dans le volume `caddy_data` et se renouvellent seuls. Une fois le DNS +posé, vérifier la délivrance avec `docker logs pleinr-caddy 2>&1 | grep -i "certificate obtained"`. -Mise à jour, dans les deux phases : `git pull && docker compose up -d --build`. +> **Vérification par l'IP** : en HTTP sur une adresse IP, la directive +> `upgrade-insecure-requests` de la CSP (`src/middleware.ts`) peut empêcher le +> navigateur de charger styles et scripts. Pour un test fidèle avant le DNS, +> passer par un tunnel SSH — `ssh -L 8080:localhost:80 utilisateur@IP` — puis +> ouvrir `http://localhost:8080` : `localhost` est une origine de confiance, la +> directive ne s'y applique pas. + +Mise à jour : `git pull && docker compose up -d --build`. ## Comptes de démonstration (seed) diff --git a/docker-compose.http.yml b/docker-compose.http.yml deleted file mode 100644 index da2583b..0000000 --- a/docker-compose.http.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Plein R — variante « HTTP simple, sans domaine ». -# -# Sert l'application directement sur le port 80 de l'hôte, joignable par -# http://IP_DU_SERVEUR. Utile pour valider une installation AVANT d'avoir -# fait pointer un nom de domaine sur le serveur : sans domaine, aucune -# autorité ne délivre de certificat, donc pas de HTTPS possible (le port 443 -# n'aurait rien à servir). -# -# Utilisation : dans .env, poser -# COMPOSE_FILE=docker-compose.yml:docker-compose.http.yml -# puis `docker compose up -d --build`. -# -# Une fois le DNS en place, on bascule en HTTPS en remplaçant simplement -# docker-compose.http.yml par docker-compose.caddy.yml dans COMPOSE_FILE -# (voir README). Caddy prend alors les ports 80 et 443. -# -# ATTENTION : en HTTP seul, la CSP de l'application (directive -# `upgrade-insecure-requests`, src/middleware.ts) peut empêcher le navigateur -# de charger les styles et scripts servis par http://IP. Pour une -# vérification fidèle depuis votre poste, passez par un tunnel SSH : -# ssh -L 8080:localhost:80 utilisateur@IP_DU_SERVEUR -# puis ouvrez http://localhost:8080 (localhost est une origine de confiance, -# la directive ne s'y applique pas). - -services: - app: - # Remplace la publication 8413 du fichier de base. - ports: !override - - "80:3000" - -networks: - # Sans Nginx Proxy Manager, personne ne crée ce réseau : Compose s'en charge. - proxy: - external: false