Documenting the server infrastructure.
Go to file
Florian Guillet 7658471f1f dl: Add myself to dl and add corresponding ssh keys 2023-02-15 12:12:48 +01:00
group_vars/all dl: Add myself to dl and add corresponding ssh keys 2023-02-15 12:12:48 +01:00
host_vars/bbb2.afpy.org Hello turn.afpy.org. 2021-12-01 23:20:10 +01:00
roles discourse: FIX: Also allow 21m in dockerized nginx. 2023-02-14 16:11:35 +01:00
.gitignore Ignore emacs backups. 2019-12-18 13:42:46 +01:00
README.md We do no longer have pydocteur, but we have munin now. 2023-02-01 18:04:52 +01:00
afpy.org.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
alain.yml Restart Alain in case of configuration change. 2022-10-09 21:43:21 +02:00
ansible.cfg Passbolt: First try (not yet stable). 2019-02-14 00:54:02 +01:00
autoconfig.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
backup.yml Backuping gitea. 2022-10-09 23:06:34 +02:00
discord-irc-sync.yml Update token for discord bot 2022-11-10 14:59:34 +01:00
discuss.yml Add self as a email alias for root. 2023-02-01 16:16:02 +01:00
dl.yml dl: Add myself to dl and add corresponding ssh keys 2023-02-15 12:12:48 +01:00
gitea.yml Add self as a email alias for root. 2023-02-01 16:16:02 +01:00
inventory exim: Disable IPv6 to avoid unavoidable blocklists. 2023-02-12 09:46:09 +01:00
logs.afpy.org.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
makemake.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
munin.yml Hello HTTP/2 2023-02-13 22:40:47 +01:00
ponyconf.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
pycon.fr.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
pydocteur.afpy.org.yml nginx: Unifying logs, we're at 600+ files in /var/log/nginx, it's unusable. 2023-02-13 23:33:35 +01:00
requirements.yml Mouve our exim4 things to exim4 role. 2022-01-30 10:53:31 +01:00
turn.yml Hello turn.afpy.org. 2021-12-01 23:20:10 +01:00
woodpecker.yml Hello woodpecker. 2023-02-01 00:18:00 +01:00

README.md

Survol des playbooks Ansible

On découpe nos playbooks Ansible par rôles :

  • pycon.yml: Pour les pycon.fr
  • backup.yml: Configure rsnapshot pour sauvegarder nos serveurs.
  • ...

En partant de là, on peut utiliser les commandes suivantes :

Après avoir cloné ce repo, installé Ansible (dans un venv), installez les roles nécessaires via :

  • ansible-galaxy install julienpalard.nginx

Récupérez le secret dans afpy/pass:

git clone https://github.com/AFPy/pass/
PASSWORD_STORE_DIR=pass/infra pass Ansible-Vault > ~/.ansible-afpy-vault

Puis pour jouer les playbooks :

  • Pour tout relancer : ansible-parallel *.yml
  • Pour configurer les PyCons : ansible-playbook pycons.yml

Faire, ne pas faire

Faire : Configurer les machines :

  • apt install,
  • fichiers de configuration,
  • créer les utilisateurs,
  • éventuellement un premier git clone pour que ça marche si c'est un site statique.

Ne pas faire :

  • Deployer. En dehors de l'éventuel premier git clone, c'est le rôle de la CI (Github Actions, ...), pas de nos playbooks.

Servers

La distinction services/serveurs :

  • Un serveur contient un nombre dans son nom : deb2.afpy.org, bbb2.afpy.org, …
  • Un service ne contient pas de chiffre dans son hostname : discuss.afpy.org, bbb.afpy.org, www.afpy.org, …

deb2.afpy.org

♥ Machine sponsorisée par Gandi ♥

C'est un VPS V-R4 2 CPUs · 4 GB RAM.

Elle héberge les services suivants :

bbb2.afpy.org

♥ Machine sponsorisée par Gandi ♥

C'est un VPS V-R8 4 CPUs · 8 GB RAM.

backup1.afpy.org

♥ Machine sponsorisée par Gandi ♥

C'est un « Gandi Cloud V5 » à Bissen au Luxembourg avec 512MB de RAM et 512GB de disque, il sauvegarde (via rsnapshot) les autres machines (voir backup.yml).

Dernière vérification de backup1.afpy.org le 2 janvier 2023 via :

ssh root@backup1.afpy.org sh check-afpy.sh

Dernière vérification de silence (chez Julien) le 2 janvier 2023 via :

ssh root@silence sh /srv/backups/check-afpy.sh

gitea1.afpy.org

♥ Machine sponsorisée par Gandi ♥

Cest un « Gandi VPS V-R1 » 1 CPU, 1 GB RAM, 25 GB disk.

Cest la machine derrière git.afpy.org, déployée via gitea.yml.

Mise à jour

Pour faire une mise à jour, se connecter en root à la machine puis exécuter :

systemctl start gitea-backup.service
backupopts="-c /etc/gitea/app.ini --file /var/backups/gitea/before-upgrade.zip" gitea-upgrade.sh

(Oui, je sais, ça fait deux sauvegardes, une par nous (avec un pg_dump), une par le script de gitea dont le SQL nest pas aussi propre que celui généré par pg_dump).

Une fois la mise à jour terminée, il est de bon goût de mettre à jour gitea_version dans gitea.yml.

Sauvegardes

Les données sont sauvegardées automatiquement via rsync sur backup1.afpy.org (voir backup.yml).

Côté VPS Gandi on a aussi un snapshot du volume tous les jours.

Restaurer une sauvegarde

Procédure testée le 2022-11-29 par mdk.

Voici la procédure pour restaurer une sauvegarde sur une nouvelle machine « from scratch ».

Commander une nouvelle machine

Typiquement chez Gandi une V-R1: 1 CPU · 1 GB RAM, avec une Debian 11, n'oubliez pas d'y mettre une clé SSH.

Nommer la machine

Typiquement gitea2.afpy.org, configurer les DNS, en profiter pour réduire le TTL de git.afpy.org puisqu'il faudra le changer à la fin.

Autoriser à se ssh en root

ssh debian@giteatest.afpy.org sudo cp /home/debian/.ssh/authorized_keys /root/.ssh/

Ajouter la machine dans l'inventaire Ansible

Ça devra donc ressembler à :

[gitea]
gitea2.afpy.org

On peut probablement supprimer l'autre qui ne marche plus...

Lancer Ansible

ansible-playbook gitea.yml

rsync la sauvegarde

J'utilise du ssh agent forwarding, si vous n'en utilisez-pas vous aurez peut-être à rsync sur votre machine d'abord.

Adapté de : https://docs.gitea.io/en-us/backup-and-restore/#restore-command-restore

Donc, depuis gitea2:

cd /var/lib/gitea/
rsync -vah backup1.afpy.org:/srv/backups/rsnapshot_afpy/daily.0/git.afpy.org/var/backups/gitea/ ./
systemctl stop gitea
rm -fr data custom
unzip gitea.zip
rm gitea.zip
mv app.ini /etc/gitea/app.ini
mv repos data/gitea-repositories
chown -R git:git .
sudo --user git psql -d gitea < gitea.sql
rm gitea.sql

Puis passer le playbook gitea.yml pour remettre les bons droits partout (le playbook démarrera aussi gitea).

Tester et mettre à jour git.afpy.org

Un rapide test peut être effectué via :

curl --resolve git.afpy.org:IP_DE_LA_NOUVELLE_MACHINE https://git.afpy.org

Puis il faut mettre à jour le CNAME de git.afpy.org pour le faire pointer vers la nouvelle machine.

discourse1.afpy.org

♥ Machine sponsorisée par Gandi ♥

C'est un VPS V-R4 2 CPUs · 4 GB RAM.

Elle héberge https://discuss.afpy.org une instance Discourse.

Déplacement du Discourse vers une nouvelle machine

Le 31 janvier 2023 Julien a déplacé le Discourse de deb2 à discourse1.

Voici la procédure
  • Ajouter les enregistrements A et AAAA de la machine.
  • Baisser le TTL du CNAME discuss.afpy.org.
  • Mettre à jour le SPF pendant qu'on y est.
  • Configurer le reverse DNS de la nouvelle machine.
  • Côté Ansible, ajouter la machine au groupe [discourse] dans le fichier inventory.
  • Copier sa clé ssh sur la machine dans /root/.ssh/authorized_keys.
  • Lancer ansible-playbook discuss.yml.
  • Lancer à la main dans /var/discourse/: ./launcher rebuild app (ça prend ~10mn).
  • Sur l'ancienne machine, faire une sauvegarde, soit via https://discuss.afpy.org/admin/backups, soit :
    ./launcher enter app
    discourse backup
    exit
    
  • Copier une sauvegarde dans /var/discourse/shared/standalone/backups/default/.
  • Restaurer la sauvegarde :
    cd /var/discourse
    ./launcher enter app
    discourse enable_restore
    discourse restore afpy-2023-01-31-215204-v20230130053144.tar.gz
    exit
    

Bien tester lenvoi demails.

Ansible

On utilies ces rôles Ansible :

roles/nginx

Ce rôle configure un nginx avec Letsencrypt en DNS-01 via l'API Gandi (nos domaines étant chez Gandi).

L'avantage du DNS-01 c'est qu'on peut configurer un nouveau serveur avant que le DNS ne pointe sur lui.

julienpalard.nginx

Ce rôle configure un nginx avec Letsencrypt en HTTP-01, on l'utilise assez peu maintenant, on l'utilise là où on ne peut pas faire de DNS-01 (pour fr.pycon.org par exemple).

Voir la doc.

common

common est un rôle "de base" permettant d'avoir une conf "normale" sur toutes nos machines (emacs et vim installés, nos authorized-keys, pas de mlocate, hostname propre, firewall, ce genre de broutilles).

BBB

Hébergé sur bbb2.afpy.org chez Gandi.

J'y ai appliqué un poil de ssh-hardening :

AuthenticationMethods publickey
LogLevel VERBOSE

Ensuite j'ai rsync les enregistrements depuis le bbb précédent.

Puis j'ai sauvegardé/restauré la DB de greenlight :

# Sur l'ancienne machine :
docker exec greenlight_db_1 /usr/bin/pg_dumpall -U postgres -f /var/lib/postgresql/data/dump.sql

# Sur la nouvelle machine :
# Copier la sauvegarde sur le nouveau serveur :
cd ~root/greenlight
rsync bbb.afpy.org:/root/greenlight/db/production/dump.sql ./

docker-compose down
rm -fr db
# Configurer le même mot de passe dans .env et docker-compose.yml que l'ancienne machine
# En profiter pour vérifier le SAFE_HOSTS dans le .env.
docker-compose up -d
# Attendre un peu avec un top sous les yeux que ça se termine vraiment
docker exec greenlight_db_1 /usr/local/bin/psql -U postgres -c "DROP DATABASE greenlight_production;"
mv dump.sql db/production/
docker exec greenlight_db_1 /usr/local/bin/psql -U postgres -f /var/lib/postgresql/data/dump.sql
rm db/production/dump.sql
docker-compose down
docker-compose up -d  # Il va s'occuper de la migration
docker-compose logs -f # pour voir si tout va bien

rsync des certificats TLS aussi :

rsync -vah bbb.afpy.org:/etc/letsencrypt/ /etc/letsencrypt/

Ça a pris un petit :

sed s/sd-106563.dedibox.fr/bbb.afpy.org/ /etc/nginx/sites-available/bigbluebutton

Il faut attendre un moment avec un top qui tourne, ruby a tout plein de truc a faire avant de démarrer.

BBB password reset

Pour accepter le password reset, BBB doit avoir :

ALLOW_MAIL_NOTIFICATIONS=true

dans /root/greenlight/.env

(Pour relire le .env: cd /root/greenlight; docker-compose down && docker-compose up -d)

Pour vérifier la conf :

docker run --rm --env-file .env bigbluebutton/greenlight:v2 bundle exec rake conf:check

Il y a des chances que ça ne passe pas, il faut laisser les mails sortir de leur conteneur Docker (par défaut il utilise sendmail DANS le conteneur).

Il faut configurer le .env tel que:

SMTP_SERVER=172.17.0.1
SMTP_PORT=25
SMTP_DOMAIN=greenlight.afpy.org
SMTP_SENDER=bbb@afpy.org

Puis vérifier qu'exim et le firewall (attention c'est peut-être ufw) les acceptent.

Configuration TURN/STUN

L'installation de BBB n'étant pas gérée par Ansible, pour le moment la conf TURN/STUN est faite à la main, c'est la seule chose à faire, elle ressemble à :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            ">

    <bean id="stun0" class="org.bigbluebutton.web.services.turn.StunServer">
        <constructor-arg index="0" value="stun:turn.afpy.org"/>
    </bean>

    <bean id="turn0" class="org.bigbluebutton.web.services.turn.TurnServer">
        <constructor-arg index="0" value="[redacte]"/>
        <constructor-arg index="1" value="turns:turn.afpy.org:443?transport=tcp"/>
        <constructor-arg index="2" value="86400"/>
    </bean>

    <bean id="stunTurnService" class="org.bigbluebutton.web.services.turn.StunTurnService">
        <property name="stunServers">
            <set>
                <ref bean="stun0" />
            </set>
        </property>
        <property name="turnServers">
            <set>
              <ref bean="turn0" />
            </set>
        </property>
        <property name="remoteIceCandidates">
            <set>
            </set>
        </property>
    </bean>
</beans>

dans /usr/share/bbb-web/WEB-INF/classes/spring/turn-stun-servers.xml.

DKIM

Le playbook exim configure une clé DKIM et signe les mails avec. Mais un humain doit la propager sur les DNS.

Le nom d'hote est le nom du serveur, donc pour deb2, d=deb2.afpy.org, et le selecteur vaut le nom de domaine avec des -, soit s=deb2-afpy-org.

TL;DR la configuration qu'il faut faire ressemble à :

deb2-afpy-org._domainkey.deb2.afpy.org. IN TXT "v=DKIM1; k=rsa; p=MIG...QAB"

La clé publique se situe dans /etc/exim4/dkim/*.pem et est donc récupérable via :

ssh root@deb2.afpy.org cat /etc/exim4/dkim/deb2-afpy-org.pem | grep -v ^- | tr -d '\n'