Déploiement VPS

Difficulté : Intermédiaire | Temps : 1–2 h | Coût : 5–20 €/mois

Prérequis

  • VPS Debian 12+ ou Ubuntu 22.04+
  • Accès root ou sudo
  • Domaine pointant vers l'IP du VPS
  • Ports 80 et 443 ouverts

1. Préparation du serveur

sudo apt update && sudo apt upgrade -y

sudo apt install -y \
    python3.12 python3.12-venv python3.12-dev \
    postgresql postgresql-contrib \
    nginx \
    git \
    certbot python3-certbot-nginx \
    build-essential libpq-dev

# Créer l'utilisateur applicatif
sudo useradd -m -s /bin/bash suddenly
sudo mkdir -p /opt/suddenly
sudo chown suddenly:suddenly /opt/suddenly

2. Base de données PostgreSQL

sudo -u postgres psql << 'EOF'
CREATE USER suddenly WITH PASSWORD 'motdepasse-securise';
CREATE DATABASE suddenly OWNER suddenly;
GRANT ALL PRIVILEGES ON DATABASE suddenly TO suddenly;
\q
EOF

3. Application

sudo -u suddenly bash << 'EOF'
cd /opt/suddenly
git clone https://github.com/RebelliousSmile/suddenly.git app
cd app
python3.12 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -e ".[federation]"
pip install gunicorn
EOF

Configuration .env

sudo -u suddenly nano /opt/suddenly/app/.env
DJANGO_SETTINGS_MODULE=config.settings.production
SECRET_KEY=votre-cle-secrete-longue
DOMAIN=votre-domaine.com
ALLOWED_HOSTS=votre-domaine.com
DATABASE_URL=postgres://suddenly:motdepasse-securise@localhost:5432/suddenly

DJANGO_SETTINGS_MODULE est indispensable : manage.py pointe par défaut sur les settings de développement. Sans cette ligne, vos migrations s'appliqueraient avec DEBUG=True et la mauvaise base. Les cookies Secure, HSTS et DEBUG=False viennent du module de production — il n'y a pas de variable à poser pour ça.

Initialisation

sudo -u suddenly bash << 'EOF'
cd /opt/suddenly/app
source venv/bin/activate
set -a; source .env; set +a
python manage.py migrate
python manage.py createcachetable
python manage.py collectstatic --noinput
python manage.py createsuperuser
EOF

Les clés RSA de fédération ne se génèrent pas à la main : Suddenly crée les clés d'instance au premier besoin, et une paire par acteur à sa création.


4. Service systemd (Gunicorn)

sudo mkdir -p /var/log/suddenly
sudo chown suddenly:suddenly /var/log/suddenly

sudo tee /etc/systemd/system/suddenly.service << 'EOF'
[Unit]
Description=Suddenly Gunicorn Daemon
After=network.target postgresql.service

[Service]
User=suddenly
Group=suddenly
WorkingDirectory=/opt/suddenly/app
Environment="PATH=/opt/suddenly/app/venv/bin"
EnvironmentFile=/opt/suddenly/app/.env
ExecStart=/opt/suddenly/app/venv/bin/gunicorn \
    --workers 3 \
    --bind unix:/opt/suddenly/suddenly.sock \
    --access-logfile /var/log/suddenly/access.log \
    --error-logfile /var/log/suddenly/error.log \
    suddenly.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable suddenly
sudo systemctl start suddenly

5. Nginx

sudo tee /etc/nginx/sites-available/suddenly << 'EOF'
upstream suddenly {
    server unix:/opt/suddenly/suddenly.sock fail_timeout=0;
}

server {
    listen 80;
    server_name votre-domaine.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name votre-domaine.com;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=31536000" always;

    access_log /var/log/nginx/suddenly_access.log;
    error_log  /var/log/nginx/suddenly_error.log;

    client_max_body_size 10M;

    location /static/ {
        alias /opt/suddenly/app/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location /media/ {
        alias /opt/suddenly/app/media/;
        expires 7d;
    }

    location / {
        proxy_pass http://suddenly;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/suddenly /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

6. SSL (Let's Encrypt)

sudo certbot --nginx -d votre-domaine.com

Certbot configure Nginx et met en place le renouvellement automatique.


7. Redis (optionnel)

Recommandé pour les instances de 50+ utilisateurs.

sudo apt install -y redis-server
sudo systemctl enable redis-server
sudo systemctl start redis-server

Ajouter dans .env :

REDIS_URL=redis://localhost:6379/0

8. Celery (optionnel)

Nécessaire pour la livraison fédérée asynchrone sur les instances de 500+ utilisateurs, ou si Redis est activé.

Deux services : le worker (qui exécute les tâches) et beat (qui les planifie — purge des citations éphémères toutes les heures, rafraîchissement des acteurs distants une fois par jour).

sudo tee /etc/systemd/system/suddenly-celery.service << 'EOF'
[Unit]
Description=Suddenly Celery Worker
After=network.target redis.service

[Service]
User=suddenly
WorkingDirectory=/opt/suddenly/app
Environment="PATH=/opt/suddenly/app/venv/bin"
EnvironmentFile=/opt/suddenly/app/.env
ExecStart=/opt/suddenly/app/venv/bin/celery \
    -A suddenly worker --loglevel=info \
    --logfile=/var/log/suddenly/celery.log
Restart=on-failure
EOF

sudo tee /etc/systemd/system/suddenly-celery-beat.service << 'EOF'
[Unit]
Description=Suddenly Celery Beat
After=network.target redis.service

[Service]
User=suddenly
WorkingDirectory=/opt/suddenly/app
Environment="PATH=/opt/suddenly/app/venv/bin"
EnvironmentFile=/opt/suddenly/app/.env
ExecStart=/opt/suddenly/app/venv/bin/celery \
    -A suddenly beat --loglevel=info \
    --scheduler django_celery_beat.schedulers:DatabaseScheduler \
    --logfile=/var/log/suddenly/celery-beat.log
Restart=on-failure
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now suddenly-celery suddenly-celery-beat

Sans Celery, ces deux tâches périodiques ne tournent pas : les citations éphémères ne seront jamais purgées. Sur une petite instance, planifiez-les en cron (voir Maintenance).


Mise à jour

sudo -u suddenly bash << 'EOF'
cd /opt/suddenly/app
git pull origin main
source venv/bin/activate
pip install --upgrade pip && pip install -e ".[federation]"
python manage.py migrate
python manage.py collectstatic --noinput
EOF

sudo systemctl restart suddenly
sudo systemctl restart suddenly-celery  # si Celery activé

Dépannage

# Statut et logs de l'application
sudo systemctl status suddenly
sudo journalctl -u suddenly -n 50

# Logs Nginx
sudo tail -f /var/log/nginx/error.log

# Test de connexion à la base
sudo -u suddenly psql -d suddenly -c "SELECT 1;"

# Erreur 502 — vérifier le socket
ls -la /opt/suddenly/suddenly.sock