Sur un serveur Linux (VPS, dédié ou interne) — 🔵 Confirmé¶
Le déploiement sur VPS ou sur un serveur interne vous donne un contrôle complet sur l’environnement. C’est adapté si votre administration gère ses propres serveurs ou utilise un hébergeur comme OVH ou Scaleway.
Indication
VPS managé ou non ? Sur un VPS « classique » (OVH, Scaleway…) non infogéré, vous gérez tout l’intérieur de la machine : c’est le cas couvert ci-dessous. Si vous disposez d’une offre infogérée, la maintenance système est assurée par le prestataire et vous pouvez sauter l’étape 1.
Prérequis¶
Un VPS ou serveur sous Linux (Ubuntu 22.04+ ou Debian 12+ recommandé)
Accès root ou sudo
Un nom de domaine configuré (enregistrement DNS de type
Apointant vers l’IP du serveur)
Étape 1 — Installation des dépendances système (si nécessaire)¶
Note
Étape à effectuer sur un serveur non infogéré. Sur une offre infogérée, passez à l’étape 2.
Mettez à jour le système puis installez les paquets nécessaires : Python, PostgreSQL, Nginx, Git et les outils de compilation requis par certaines dépendances Python.
sudo apt update && sudo apt upgrade -y
sudo apt install -y \
python3 python3-venv python3-dev \
postgresql postgresql-contrib \
nginx git \
build-essential libpq-dev
python3-venvpermet de créer des environnements virtuels.libpq-devetbuild-essentialsont nécessaires pour compilerpsycopg(le pilote PostgreSQL de Python).postgresql-contribajoute des extensions utiles à PostgreSQL.
Étape 2 — Mise en place de la base de données¶
Création d’une base de données PostgreSQL avec les droits correspondants :
sudo -u postgres psql
puis
CREATE USER sites_conformes WITH PASSWORD 'mot_de_passe_solide';
CREATE DATABASE sites_conformes_db OWNER sites_conformes;
\q
Étape 3 — Déploiement de l’application¶
Clonez le dépôt (par exemple dans /opt/sites-conformes),
installez les dépendances, configurez l’environnement,
puis initialisez le site. Voici les deux voies possibles, côte à côte.
Voie A — uv + just (voie officielle du projet)¶
cd /opt/sites-conformes
git clone https://github.com/numerique-gouv/sites-conformes.git .
git checkout production
# Installer uv si nécessaire : https://docs.astral.sh/uv/
# Éditer le .env (voir modèle ci-dessus)
# Installation des dépendances + initialisation complète du site
just init
# (just init = `uv sync --no-group dev` puis `just deploy`)
# Création du compte administrateur
just createsuperuser
just init installe les dépendances de production puis lance
just deploy, qui enchaîne : migrate, collectstatic,
create_starter_pages, import_page_templates,
import_illustration_images et l’indexation (update_index).
Voie B — pip + venv (voie classique)¶
cd /opt/sites-conformes
git clone https://github.com/numerique-gouv/sites-conformes.git .
git checkout production
# Environnement virtuel + dépendances
python3 -m venv venv # création de l’environnement virtuel
source venv/bin/activate # activation de l’environnement virtuel
pip install . # dépendances déclarées dans pyproject.toml
# Éditer le .env
# Initialisation manuelle du site
python manage.py migrate
python manage.py collectstatic --noinput --ignore="*.sass"
python manage.py createsuperuser
python manage.py set_config
python manage.py create_starter_pages
python manage.py import_page_templates
python manage.py import_illustration_images
python manage.py update_index
Note
Le projet est aujourd’hui outillé autour de uv (fichiers pyproject.toml
et uv.lock) et ne fournit pas de requirements.txt.
La voie A (uv + just) est donc la référence et garantit des versions de
dépendances identiques à celles testées par l’équipe.
La voie B (pip) reste possible via pip install .,
mais elle est surtout utile à titre pédagogique ou dans les environnements où
uv n’est pas disponible.
Pour la liste complète des réglages à mettre dans le .env, voir la
référence des variables d’environnement.
Étape 4 — Configurer un serveur d’application (Gunicorn)¶
Gunicorn est le serveur WSGI qui exécute l’application Django en production
(on n’utilise jamais runserver en production, qui est réservé au développement).
Pour un test rapide, le projet fournit la recette :
just run_gunicorn
Pour un fonctionnement permanent (démarrage automatique, redémarrage en cas de
plantage), gérez Gunicorn avec systemd.
Créez /etc/systemd/system/sites-conformes.service :
[Unit]
Description=Gunicorn pour Sites Conformes
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/sites-conformes
EnvironmentFile=/opt/sites-conformes/.env
ExecStart=/opt/sites-conformes/venv/bin/gunicorn \
--workers 3 \
--bind unix:/opt/sites-conformes/gunicorn.sock \
config.wsgi:application
[Install]
WantedBy=multi-user.target
EnvironmentFile=/opt/sites-conformes/.envindique à systemd de charger les variables d’environnement depuis le fichier.envcréé à l’étape 3. C’est ainsi que Gunicorn récupèreSECRET_KEY,DATABASE_URL, etc. Adaptez le chemin si vous avez installé l’application ailleurs.config.wsgi:applicationest le chemin vers le module WSGI ; adaptezconfigau nom réel du dossier de configuration du projet.Le
--bind unix:...sockcrée un socket Unix (un fichier) que Nginx utilisera pour parler à Gunicorn : plus rapide et plus sûr qu’un port réseau pour une communication locale.Règle empirique pour
--workers:(2 × nombre de cœurs CPU) + 1.Avec
uv, remplacez le chemin de l’ExecStartparuv run gunicorn …exécuté dans le répertoire du projet.
Activez et démarrez le service :
sudo systemctl daemon-reload
sudo systemctl enable --now sites-conformes
sudo systemctl status sites-conformes
Étape 5 — Configurer un reverse proxy (Nginx)¶
Nginx se place devant Gunicorn : il reçoit les requêtes des visiteurs, sert directement les fichiers statiques et médias, et transmet le reste à Gunicorn.
Astuce
Le projet fournit un script générateur de configuration Nginx, accessible via
just nginx-generate-config-file.
Vous pouvez l’utiliser comme point de départ plutôt que de tout écrire à la main.
Activez le site et rechargez Nginx :
sudo ln -s /etc/nginx/sites-available/sites-conformes /etc/nginx/sites-enabled/
sudo nginx -t # vérifie la syntaxe de la configuration
sudo systemctl reload nginx
Étape 6 — Indexation de la recherche¶
Les contenus des pages sont indexés pour permettre la recherche sur le site, par
la commande update_index (cf. la documentation de Wagtail).
Elle est déjà lancée par just deploy à chaque déploiement.
Il est recommandé d’y ajouter une réindexation hebdomadaire, pour corriger d’éventuels écarts entre l’index et les contenus. Ajoutez une tâche cron :
crontab -e
# Ajouter :
0 3 * * 0 /opt/sites-conformes/venv/bin/python /opt/sites-conformes/manage.py update_index
Cette ligne lance
update_indexchaque dimanche à 3 h du matin (0 3 * * 0= minute 0, heure 3, tous les jours du mois, tous les mois, jour de semaine 0 = dimanche).
Mise à jour (serveur Linux)¶
Sauvegarder la base de données :
pg_dump -U sites_conformes sites_conformes_db > sauvegarde_$(date +%F).sql
Récupérer la dernière version du code et la branche
production.Mettre à jour les dépendances et réinitialiser le contenu généré :
Voie A (uv + just) :
just update(=
uv sync --no-group devpuisjust deploy, qui inclut migrations, fichiers statiques et indexation).Voie B (pip + venv) :
source venv/bin/activate pip install . python manage.py migrate python manage.py collectstatic --noinput --ignore="*.sass"
Redémarrer le service :
sudo systemctl restart sites-conformes
Astuce
Ne pas confondre just update et just upgrade :
updatemet à jour l’application (synchronise les dépendances verrouillées et redéploie).upgrademonte les versions des dépendances (uv lock --upgrade,pre-commit autoupdate,npm update) : c’est une opération de maintenance du dépôt, à réserver au développement, pas à un serveur de production.
Dans le cas d’un déploiement en RIE / réseau privé¶
Important
Le Réseau Interministériel de l’État (RIE) est le réseau interne sécurisé reliant les administrations françaises. Le déploiement sur le RIE implique des contraintes réseau spécifiques.
Contraintes principales [À FAIRE VÉRIFIER / RELIRE]¶
Pas d’accès direct à Internet : tout le trafic sortant passe par des passerelles contrôlées. L’accès aux dépôts pip, npm, et aux registries Docker peut être bloqué.
Filtrage DNS : seuls les domaines autorisés sont résolus.
Proxy HTTP obligatoire : les requêtes sortantes doivent passer par le proxy du ministère.
Certificats spécifiques : le RIE utilise ses propres autorités de certification. Les certificats Let’s Encrypt ne sont pas utilisables.
Restrictions sur les ports : seuls certains ports sont ouverts (typiquement 80, 443).
Adaptations recommandées [À COMPLÉTER / FAIRE RELIRE PAR LES CONCERNÉ·ES]¶
Pas d’accès Internet sortant : téléchargez les dépendances Python en amont depuis une machine connectée, puis transférez-les sur le serveur.
Accès au dépôt : clonez le dépôt depuis une machine connectée puis transférez l’archive, ou configurez un miroir Git interne.
DNS interne : nom de domaine résolu par le DNS interne à l’administration.
Proxy sortant : si un proxy HTTP est nécessaire, configurez les variables
HTTP_PROXYetHTTPS_PROXYdans l’environnement.Certificats : installez l’autorité de certification interne dans le magasin de certificats du système.