Initial commit: VPS tutorial complet (105 etapes)

This commit is contained in:
Script Shadow
2026-04-08 16:15:11 +02:00
commit acbe11489c
18 changed files with 1848 additions and 0 deletions

57
01-prerequis.md Normal file
View File

@@ -0,0 +1,57 @@
# 1. Prerequis et Choix
## Choix de l'hebergeur VPS
**Recommande : Contabo** (bon rapport qualite/prix)
- VPS S : 2 vCPU / 4 GB RAM (~5 EUR/mois)
- VPS M : 4 vCPU / 8 GB RAM (~10 EUR/mois) - recommande
- OS : Ubuntu 24.04 LTS
## Choix du registrar
**Recommande : OVH**
- Interface complete (glue records, NS personnalises, DNSSEC)
- Pas besoin de contacter le support pour les modifications
- Propagation DNS rapide
**Eviter :** Cloud4Africa/MTN pour les .ci (support lent, interface buggee pour les NS personnalises)
**Alternative :** Cloudflare (DNS gratuit, protection DDoS, mais pas de registrar pour tous les TLD)
## Choix du panel
### ISPConfig (utilise dans ce guide)
- Complet : multi-serveur, revendeur, quotas
- Plus lourd et interface ancienne
- Documentation : https://vps-installation.readthedocs.io/fr/latest/
### HestiaCP (recommande pour prochain VPS)
- Plus leger, interface moderne
- Mises a jour frequentes
- Un seul serveur uniquement
- Documentation : https://docs.hestiacp.com/
## Configuration initiale chez l'hebergeur
1. Commander le VPS avec Ubuntu 24.04
2. Noter l'IP publique IPv4 et IPv6
3. Se connecter en SSH : `ssh root@<IP>`
4. Changer le mot de passe root : `passwd`
## Configuration chez le registrar (OVH)
1. Acheter le domaine
2. Creer les **glue records** :
- `ns1.<DOMAINE>` -> `<IP>`
- `ns2.<DOMAINE>` -> `<IP>`
3. Changer les **nameservers** vers :
- `ns1.<DOMAINE>`
- `ns2.<DOMAINE>`
> **Note :** OVH verifie que le serveur DNS repond avant d'accepter le changement. Il faut d'abord installer ISPConfig et creer la zone DNS (etape 3-4).
## Pour les domaines .ci chez MTN
Les domaines .ci ne supportent pas les glue records vers le meme domaine. Solution :
- Utiliser les NS de votre domaine principal (ex: `ns1.z-ana.com` pour `stlab.ci`)
- Modifier les NS chez MTN vers `ns1.<DOMAINE_PRINCIPAL>` et `ns2.<DOMAINE_PRINCIPAL>`

210
02-config-base.md Normal file
View File

@@ -0,0 +1,210 @@
# 2. Configuration de Base
## Creer un utilisateur
```bash
adduser <USER>
usermod -a -G sudo <USER>
```
## Configurer /etc/hosts
```bash
cat > /etc/hosts << 'EOF'
127.0.0.1 localhost
127.0.1.1 <FQDN> <HOSTNAME>
<IP> <FQDN> <HOSTNAME>
# IPv6
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
```
## Verifier le hostname
```bash
hostnamectl set-hostname <FQDN>
hostname -f
# Doit afficher : <FQDN>
```
## Editeur par defaut
```bash
apt install vim micro
update-alternatives --config editor
# Choisir micro ou vim
```
## Installer etckeeper
```bash
apt update && apt install etckeeper
```
## Mettre a jour les sources apt
Ubuntu 24.04 utilise le format deb822 (`/etc/apt/sources.list.d/ubuntu.sources`).
Verifier que `main universe restricted multiverse` et `backports` sont presents.
```bash
apt update && apt dist-upgrade && apt autoremove
```
## Paquets de base
```bash
apt install curl wget ntpdate apt-transport-https apt-listchanges apt-file apt-rdepends man
```
## Locale FR
```bash
apt install locales
dpkg-reconfigure locales
# Selectionner fr_FR.UTF-8
apt install task-french
```
## Debfoster
```bash
apt install debfoster
debfoster
```
### Script keeper pour etckeeper
Creer `/etc/etckeeper/pre-commit.d/35debfoster` :
```bash
#!/bin/sh
set -e
LANG=C
export LANG
shellquote() {
sed -e "s/'/'\"'\"'/g" -e "s/^/'/" -e "s/$/'/"
}
if [ "$VCS" = git ] || [ "$VCS" = hg ] || [ "$VCS" = bzr ] || [ "$VCS" = darcs ]; then
debfoster -q -k /etc/keepers
chmod 600 /etc/keepers
sed -i "1i\\# debfoster file" /etc/keepers
sed -i "1i\\# Generated by etckeeper. Do not edit." /etc/keepers
if [ "$VCS" = git ]; then
git add keepers
fi
fi
```
```bash
chmod 755 /etc/etckeeper/pre-commit.d/35debfoster
etckeeper commit
```
## Mises a jour automatiques
```bash
apt install unattended-upgrades
```
## Interdire le login root SSH
```bash
# Verifier dans /etc/ssh/sshd_config :
PermitRootLogin no
```
## Sudo sans mot de passe
```bash
addgroup --system sudonp
usermod -a -G sudonp <USER>
echo '%sudonp ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/010_sudonp
chmod 440 /etc/sudoers.d/010_sudonp
```
> **Important :** Deconnectez-vous et reconnectez-vous pour activer le groupe.
## Neofetch + MOTD
```bash
apt install neofetch
```
Creer `/etc/neofetch.conf` :
```bash
print_info() {
info title
info underline
info "OS" distro
info "Host" model
info "Kernel" kernel
info "Uptime" uptime
info "Packages" packages
info "Shell" shell
info "CPU" cpu
info "CPU Usage" cpu_usage
prin "Load" "$(cat /proc/loadavg | awk '{print $1, $2, $3}')"
info "GPU" gpu
info "Memory" memory
info "Disk" disk
info "Local IP" local_ip
info "Public IP" public_ip
info "Users" users
info "Locale" locale
info cols
}
title_fqdn="on"
memory_percent="on"
memory_unit="mib"
package_managers="on"
image_backend="ascii"
cpu_temp="on"
```
Creer `/etc/update-motd.d/20-neofetch` :
```bash
#!/bin/sh
neofetch --config /etc/neofetch.conf
```
```bash
chmod 755 /etc/update-motd.d/20-neofetch
```
## Script MOTD mises a jour
```bash
apt install python3-apt
```
Creer `/etc/update-motd.d/30-updates` avec le script Python de detection des mises a jour (voir scripts/setup_motd_updates.py).
```bash
chmod 755 /etc/update-motd.d/30-updates
```
## Installer dselect
```bash
apt install dselect
```
## Ajouter un fichier de swap (4 Go)
```bash
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile swap swap defaults 0 0' >> /etc/fstab
echo 'vm.swappiness = 5' >> /etc/sysctl.conf
sysctl -p
```

55
03-bis-hestiacp.md Normal file
View File

@@ -0,0 +1,55 @@
# 3-bis. HestiaCP (Alternative a ISPConfig)
## Pourquoi HestiaCP ?
| Aspect | ISPConfig | HestiaCP |
|--------|-----------|----------|
| Interface | Ancienne | Moderne, intuitive |
| Performance | Plus lourd | Plus leger, plus rapide |
| Multi-serveur | Oui | Non |
| Mises a jour | Lentes | Frequentes |
| Communaute | Grande, ancienne | Plus petite, plus active |
**Recommande pour un seul serveur.**
## Installation
```bash
wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh
bash hst-install.sh
```
Options recommandees :
- Apache + Nginx (Nginx en proxy)
- MariaDB
- Bind9
- Exim + Dovecot + ClamAV + SpamAssassin
- Let's Encrypt
## Configuration post-installation
L'installeur configure automatiquement :
- Firewall (iptables)
- SSL Let's Encrypt pour le panel
- Bind9 pour DNS
- Mail complet
## Acces
```
https://<DOMAINE>:8083
```
## Documentation
- Site : https://hestiacp.com/
- Docs : https://docs.hestiacp.com/
- GitHub : https://github.com/hestiacp/hestiacp
## Differences avec ce guide
Si vous utilisez HestiaCP, les sections DNS, Mail, et Sites Web seront differentes dans l'interface mais les concepts restent les memes :
- Creer une zone DNS avec les templates
- Creer un site web avec SSL Let's Encrypt
- Creer un domaine mail avec DKIM/DMARC
- Les services Docker (Portainer, Wireguard, etc.) restent identiques

67
03-ispconfig.md Normal file
View File

@@ -0,0 +1,67 @@
# 3. ISPConfig
## Installation
```bash
wget -O - https://get.ispconfig.org | sh -s -- --use-ftp-ports=40110-40210 --unattended-upgrades
```
> **Important :** Notez les identifiants admin et le mot de passe MySQL root affiches a la fin.
## Resoudre les conflits
Si Apache ne demarre pas, verifier si un autre service occupe le port 80 :
```bash
ss -tlnp | grep ':80'
```
Si c'est Caddy ou Nginx :
```bash
systemctl stop caddy && systemctl disable caddy
systemctl restart apache2
```
## Desactiver UFW
ISPConfig gere le firewall via iptables. Ne pas utiliser UFW en parallele.
```bash
ufw disable
```
## Configurer le firewall ISPConfig
Dans ISPConfig > **System > Firewall** :
**Open TCP ports :**
```
20,21,22,25,53,80,110,143,443,465,587,993,995,2812,3306,4190,8080,8081,10000,50022,40110:40210,7880,7881,5349
```
**Open UDP ports :**
```
53,7882,3478,51820
```
## Configuration initiale ISPConfig
### Main config
- **System > Main config > Sites :**
- Create subdomains as web site : **Yes**
- Create aliasdomains as web site : **Yes**
- **System > Main config > Mail :**
- Renseigner email et nom administrateur
### Content Filter (Rspamd)
- **System > Server Config > votre serveur > Mail :**
- Content Filter : **Rspamd**
## Acces
```
https://<DOMAINE>:8080
```
> **Piege :** Certains hebergeurs (Contabo) bloquent le port 8080 au niveau firewall externe. Verifier l'acces et debloquer si necessaire.

92
04-dns.md Normal file
View File

@@ -0,0 +1,92 @@
# 4. DNS
## Templates DNS
Creer deux templates dans ISPConfig > **DNS > DNS Templates** :
### Template IPV4 autoNS
**Fields :** Domain, IP Address, Email, DKIM, DNSSEC
```
[ZONE]
origin={DOMAIN}.
ns=ns1.<DOMAINE_SERVEUR>.
mbox={EMAIL}.
refresh=7200
retry=540
expire=604800
minimum=3600
ttl=3600
[DNS_RECORDS]
A|{DOMAIN}.|{IP}|0|3600
A|www|{IP}|0|3600
A|mail|{IP}|0|3600
A|autoconfig|{IP}|0|3600
A|autodiscover|{IP}|0|3600
A|webmail|{IP}|0|3600
CNAME|ftp|{DOMAIN}|0|3600
CNAME|smtp|{DOMAIN}|0|3600
CNAME|pop3|{DOMAIN}|0|3600
CNAME|imap|{DOMAIN}|0|3600
NS|{DOMAIN}.|ns1.<DOMAINE_SERVEUR>.|0|3600
NS|{DOMAIN}.|ns2.<DOMAINE_SERVEUR>.|0|3600
MX|{DOMAIN}.|mail.{DOMAIN}.|10|3600
TXT|{DOMAIN}.|v=spf1 mx a ~all|0|3600
SRV|_imaps._tcp|0 1 993 mail.{DOMAIN}|0|3600
SRV|_submission._tcp|0 1 465 mail.{DOMAIN}|0|3600
```
### Template IPV6 autoNS
Meme chose que IPV4 + ajout des AAAA :
**Fields :** Domain, IP Address, IPv6 Address, Email, DKIM, DNSSEC
Ajouter dans [DNS_RECORDS] :
```
AAAA|{DOMAIN}.|{IPV6}|0|3600
AAAA|www|{IPV6}|0|3600
AAAA|mail|{IPV6}|0|3600
AAAA|autoconfig|{IPV6}|0|3600
AAAA|autodiscover|{IPV6}|0|3600
AAAA|webmail|{IPV6}|0|3600
```
> **Important :** Les NS pointent vers `ns1.<DOMAINE_SERVEUR>` (votre domaine principal), pas `ns1.{DOMAIN}`. Cela evite les problemes de glue records pour les domaines heberges.
## Creer une zone DNS
ISPConfig > **DNS > Add DNS Zone > DNS Wizard**
- Template : Template IPV6 autoNS
- Domain : `<DOMAINE>`
- IP : `<IP>`
- IPv6 : `<IPV6>`
- Email : votre email
- DKIM : cocher
- DNSSEC : decocher (activer plus tard)
## Configurer les NS chez le registrar
### OVH
1. Creer les glue records : `ns1.<DOMAINE>` et `ns2.<DOMAINE>` -> `<IP>`
2. Changer les nameservers vers `ns1.<DOMAINE>` et `ns2.<DOMAINE>`
> **Note :** OVH verifie que Bind9 repond avant d'accepter. Creer la zone DNS dans ISPConfig d'abord.
### Domaines .ci (MTN/Cloud4Africa)
Pointer les NS vers le domaine serveur principal :
- `ns1.<DOMAINE_SERVEUR>`
- `ns2.<DOMAINE_SERVEUR>`
## Verification
```bash
dig @8.8.8.8 <DOMAINE> NS +short
dig @8.8.8.8 <DOMAINE> A +short
dig @8.8.8.8 mail.<DOMAINE> A +short
```

87
05-webmin.md Normal file
View File

@@ -0,0 +1,87 @@
# 5. Webmin
## Installation
```bash
curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh
sh setup-repos.sh
rm setup-repos.sh
apt update && apt install webmin
```
## Configurer le compte admin
Remplacer `root` par `<USER>` dans :
- `/etc/webmin/miniserv.users`
- `/etc/webmin/webmin.acl`
```bash
sed -i 's/root:/<USER>:/' /etc/webmin/miniserv.users
sed -i 's/root:/<USER>:/' /etc/webmin/webmin.acl
service webmin restart
```
## Desactiver SSL natif (utiliser proxy Apache)
Webmin a des problemes avec SSL sur certaines versions. Utiliser un proxy Apache :
```bash
sed -i 's/ssl=1/ssl=0/' /etc/webmin/miniserv.conf
```
Ajouter dans `/etc/webmin/config` :
```
webprefixnoredir=1
relative_redir=1
```
Ajouter dans `/etc/webmin/miniserv.conf` :
```
referers=webmin.<DOMAINE>
redirect_port=443
redirect_ssl=1
```
```bash
systemctl restart webmin
```
## Creer le sous-domaine
1. DNS : A record `webmin` -> `<IP>`
2. ISPConfig > Sites > Subdomain (vhost) :
- Hostname : `webmin`
- Domain : `<DOMAINE>`
- Web folder : `webmin`
- SSL + Let's Encrypt
- Rewrite HTTP to HTTPS
3. Apache Directives :
```apache
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyRequests Off
ProxyPass /stats !
ProxyPass /.well-known/acme-challenge !
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
ProxyPreserveHost On
ProxyPass / http://localhost:10000/
ProxyPassReverse / http://localhost:10000/
RedirectMatch ^/$ https://webmin.<DOMAINE>
```
## Ajouter le port au firewall
ISPConfig > System > Firewall : ajouter `10000` aux TCP ports.
## Acces
```
https://webmin.<DOMAINE>
```

163
06-monitoring.md Normal file
View File

@@ -0,0 +1,163 @@
# 6. Monitoring
## Munin
### Installation
```bash
apt install libcgi-fast-perl libapache2-mod-fcgid
a2enmod fcgid
apt install munin munin-node munin-plugins-extra logtail libcache-cache-perl
```
### Plugins MySQL
```bash
cd /etc/munin/plugins
ln -s /usr/share/munin/plugins/mysql_ mysql_
ln -s /usr/share/munin/plugins/mysql_bytes mysql_bytes
ln -s /usr/share/munin/plugins/mysql_innodb mysql_innodb
ln -s /usr/share/munin/plugins/mysql_isam_space_ mysql_isam_space_
ln -s /usr/share/munin/plugins/mysql_queries mysql_queries
ln -s /usr/share/munin/plugins/mysql_slowqueries mysql_slowqueries
ln -s /usr/share/munin/plugins/mysql_threads mysql_threads
```
### Base de donnees Munin
```sql
CREATE SCHEMA munin_innodb;
USE munin_innodb;
CREATE TABLE something (anything int) ENGINE=InnoDB;
GRANT SELECT ON munin_innodb.* TO 'munin'@'localhost' IDENTIFIED BY 'munin';
FLUSH PRIVILEGES;
```
### Configuration
Editer `/etc/munin/munin.conf` :
- Decommenter `dbdir`, `htmldir`, `logdir`, `rundir`, `tmpldir`
- Remplacer `[localhost.localdomain]` par `[munin.<DOMAINE>]`
### Apache auth
```bash
a2enconf munin
htpasswd -c /etc/munin/munin-htpasswd admin
```
Editer `/etc/apache2/conf-enabled/munin.conf` avec auth basic (voir scripts/setup_munin_config.py).
### Auto-configure plugins
```bash
cd /etc/munin/plugins
munin-node-configure --shell --families=contrib,auto | sh -x
service munin-node restart
service apache2 restart
```
## Monit
### Installation
```bash
apt install monit
```
### Configuration
Creer `/etc/monit/conf.d/monitrc.local` :
```
set daemon 60
set logfile syslog facility log_daemon
set mailserver localhost
set mail-format { from: monit@<DOMAINE> }
set alert <EMAIL>
set httpd port 2812 and
SSL ENABLE
PEMFILE /usr/local/ispconfig/interface/ssl/ispserver.pem
allow admin:"<MOT_DE_PASSE>"
```
### Fichiers de monitoring
Creer dans `/etc/monit/conf-enabled/` les fichiers pour : mariadb, pureftpd, named, sshd, apache2, memcached, ntpd, dovecot, postfix, redis.
Voir `scripts/setup_monit.py` pour le script complet.
```bash
mkdir /var/www/html/monit
echo "hello" > /var/www/html/monit/token
service apache2 restart
service monit restart
```
Ajouter port 2812 au firewall ISPConfig.
## Grafana + Prometheus
### Installation
```bash
echo "deb https://packages.grafana.com/oss/deb stable main" >> /etc/apt/sources.list.d/grafana.list
cd /etc/apt/trusted.gpg.d && wget https://packages.grafana.com/gpg.key -O grafana.asc
apt update
apt install grafana prometheus prometheus-mysqld-exporter prometheus-apache-exporter prometheus-bind-exporter prometheus-process-exporter
```
### Configurer Grafana sur port 3100
Editer `/etc/grafana/grafana.ini` :
```ini
http_port = 3100
```
### Configurer Prometheus
Editer `/etc/prometheus/prometheus.yml` — ajouter les jobs : prometheus, node, dns-master, apache, process, mysql.
> **Piege :** Ne pas dupliquer les jobs (erreur "found multiple scrape configs with job name").
### Sous-domaine Grafana
DNS A `grafana` -> `<IP>`, puis sous-domaine ISPConfig avec proxy vers `http://localhost:3100/`.
### Demarrer
```bash
systemctl enable grafana-server && systemctl start grafana-server
service prometheus restart
```
Login par defaut : **admin / admin**
## Loki + Promtail
### Loki
```bash
cd /usr/local/bin
# Telecharger la derniere version depuis https://github.com/grafana/loki/releases/
wget <URL_LOKI_LINUX_AMD64> -O loki.zip
unzip loki.zip && mv loki-linux-amd64 loki && chmod 755 loki && rm loki.zip
```
Creer `/etc/config-loki.yml` et `/etc/systemd/system/loki.service`.
> **Piege :** Loki v3 a un format de config different de v2. Utiliser `schema: v13` et `store: tsdb`.
### Promtail
```bash
# Promtail n'existe plus dans Loki v3, utiliser la derniere v2
wget https://github.com/grafana/loki/releases/download/v2.9.10/promtail-linux-amd64.zip -O promtail.zip
unzip promtail.zip && mv promtail-linux-amd64 promtail && chmod 755 promtail && rm promtail.zip
```
Creer `/etc/config-promtail.yml` et `/etc/systemd/system/promtail.service`.
### Ajouter Loki dans Grafana
Configuration > Data Sources > Add > Loki > URL : `http://127.0.0.1:3101`

151
07-mail.md Normal file
View File

@@ -0,0 +1,151 @@
# 7. Mail
## Desactiver amavisd
```bash
systemctl stop amavisd-new 2>/dev/null
systemctl disable amavisd-new 2>/dev/null
```
## Configurer Rspamd
Voir `scripts/setup_rspamd.py` pour le script complet. Fichiers crees :
- `/etc/rspamd/local.d/classifier-bayes.conf` — apprentissage Bayes + Redis
- `/etc/rspamd/local.d/redis.conf` — serveur Redis
- `/etc/rspamd/local.d/metrics.conf` — seuils spam
- `/etc/rspamd/local.d/history_redis.conf` — historique
- `/etc/rspamd/local.d/url_reputation.conf` — reputation URLs
- `/etc/rspamd/local.d/mx_check.conf` — verification MX
- `/etc/rspamd/local.d/neural.conf` — reseau de neurones
- `/etc/rspamd/local.d/neural_group.conf` — groupes neurones
- `/etc/rspamd/local.d/milter_headers.conf` — headers spam
- `/etc/rspamd/local.d/arc.conf` — protocole ARC
- `/etc/rspamd/local.d/antivirus.conf` — ClamAV
- `/etc/rspamd/local.d/groups.conf` — groupes antivirus
- `/etc/rspamd/local.d/antivirus_group.conf` — detection virus
```bash
a2enmod proxy
systemctl restart apache2
systemctl restart rspamd
```
## Dovecot Sieve (apprentissage spam/ham)
Voir `scripts/setup_dovecot_sieve.py`. Configure :
- Deplacement vers Junk = apprend comme spam
- Deplacement depuis Junk = apprend comme ham
- Quota warning a 90%
Installer les plugins necessaires :
```bash
apt install dovecot-sieve dovecot-managesieved
```
## Creer le domaine mail
ISPConfig > **Email > Domain > Add new Domain**
- Domain : `<DOMAINE>`
- Enable DKIM : cocher
- Generate DKIM Private-key
## Ajouter DMARC
ISPConfig > DNS > Zones > `<DOMAINE>` > Records > TXT :
- Hostname : `_dmarc`
- Text : `v=DMARC1;p=reject;sp=quarantine;pct=100;rua=mailto:<EMAIL>`
## Verifier SPF
Doit deja exister (cree par le template) :
```
TXT <DOMAINE>. v=spf1 mx a ~all
```
## Configurer Postfix
```bash
# Verifier dans /etc/postfix/main.cf :
myhostname = mail.<DOMAINE>
```
## Sous-domaine webmail (Roundcube)
1. DNS A `mail` -> `<IP>`
2. ISPConfig > Sites > Subdomain (vhost) : `mail.<DOMAINE>`
3. Apache Directives :
```apache
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyRequests Off
ProxyPass /stats !
ProxyPass /.well-known/acme-challenge !
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
SSLProxyEngine On
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyPass /webmail https://localhost:8080/webmail/
ProxyPass / https://localhost:8080/webmail/
ProxyPassReverse / https://localhost:8080/webmail/
RedirectMatch ^/$ https://mail.<DOMAINE>
```
## Sous-domaine Rspamd
Meme principe avec proxy vers `https://<DOMAINE>:8081/rspamd/`.
## Autoconfig (Thunderbird/Android)
1. Sous-domaine `autoconfig.<DOMAINE>` avec Apache Directives :
```apache
<FilesMatch "^.+\.xml$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>
<FilesMatch "^.+\.json$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>
AddHandler application/x-httpd-php .php .xml .json
<IfModule mod_speling.c>
CheckCaseOnly on
CheckSpelling on
</IfModule>
```
2. Creer le fichier `autoconfig/mail/config-v1.1.xml` (voir scripts/setup_autoconfig.py)
3. Mettre a jour PHP-FPM : ajouter `.xml .json` dans `security.limit_extensions`
## Autodiscover (Outlook)
Meme sous-domaine pointant vers le meme dossier `autoconfig`. Creer `autoconfig/Autodiscover/Autodiscover.xml`.
## Creer une boite mail
ISPConfig > **Email > Email Mailbox > Add new Mailbox**
## Tester l'envoi
```bash
echo "Test" | mail -s "Test" -r contact@<DOMAINE> votre@email.com
```
## MAILER_DSN pour Symfony
```
MAILER_DSN=smtp://127.0.0.1:25?auto_tls=false
```

78
08-sni-mail.md Normal file
View File

@@ -0,0 +1,78 @@
# 8. SNI Mail Multi-Domaines
## Probleme
Par defaut, Dovecot/Postfix servent un seul certificat SSL pour tous les domaines mail. Les clients (iPhone, Gmail app) refusent la connexion si le certificat ne correspond pas au serveur configure.
## Solution : SNI (Server Name Indication)
### Dovecot SNI
Editer `/etc/dovecot/dovecot.conf`, apres la ligne `ssl_prefer_server_ciphers = no` ajouter :
```
# SNI per domain
local_name mail.<DOMAINE1> {
ssl_cert = </chemin/vers/mail.<DOMAINE1>-le.crt
ssl_key = </chemin/vers/mail.<DOMAINE1>-le.key
}
local_name mail.<DOMAINE2> {
ssl_cert = </chemin/vers/mail.<DOMAINE2>-le.crt
ssl_key = </chemin/vers/mail.<DOMAINE2>-le.key
}
```
> **Piege :** Ne pas mettre le SNI dans `conf.d/10-ssl.conf` — ISPConfig ou le `dovecot.conf` principal ecrase les valeurs. Toujours ajouter directement dans `dovecot.conf`.
### Trouver les certificats
ISPConfig stocke les certificats LE dans le dossier SSL du site :
```bash
find /var/www/clients/ -name "mail.<DOMAINE>-le.*"
```
Format : `/var/www/clients/clientX/webY/ssl/mail.<DOMAINE>-le.crt` et `.key`
### Postfix SNI
Creer `/etc/postfix/sni_map` :
```
mail.<DOMAINE1> /chemin/vers/mail.<DOMAINE1>-le.key /chemin/vers/mail.<DOMAINE1>-le.crt
mail.<DOMAINE2> /chemin/vers/mail.<DOMAINE2>-le.key /chemin/vers/mail.<DOMAINE2>-le.crt
```
```bash
postmap -F hash:/etc/postfix/sni_map
```
Ajouter dans `/etc/postfix/main.cf` :
```
tls_server_sni_maps = hash:/etc/postfix/sni_map
```
### Redemarrer
```bash
systemctl restart dovecot
systemctl restart postfix
```
### Verification
```bash
echo | openssl s_client -connect <IP>:993 -servername mail.<DOMAINE1> 2>&1 | grep "subject="
# Doit afficher : subject=CN = mail.<DOMAINE1>
echo | openssl s_client -connect <IP>:993 -servername mail.<DOMAINE2> 2>&1 | grep "subject="
# Doit afficher : subject=CN = mail.<DOMAINE2>
```
## Certificat par defaut ISPConfig
Le certificat dans `/usr/local/ispconfig/interface/ssl/ispserver.crt` est utilise pour :
- ISPConfig panel (port 8080)
- Dovecot/Postfix par defaut (quand SNI ne match pas)
Garder le certificat du domaine principal du serveur (`<DOMAINE>`) comme defaut.

102
09-docker.md Normal file
View File

@@ -0,0 +1,102 @@
# 9. Docker
## Installation
Si Docker n'est pas deja installe :
```bash
apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
Verifier :
```bash
docker run hello-world
```
## Docker Swarm
```bash
docker swarm init
docker node ls
```
## Portainer
1. DNS A `portainer` -> `<IP>`
2. Sous-domaine ISPConfig `portainer.<DOMAINE>` avec proxy :
```apache
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyRequests Off
ProxyPass /stats !
ProxyPass /.well-known/acme-challenge !
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
ProxyPreserveHost On
ProxyPass / http://localhost:9050/
ProxyPassReverse / http://localhost:9050/
RedirectMatch ^/$ https://portainer.<DOMAINE>
```
3. Installer :
```bash
docker volume create portainer_data
docker run -d -p 9050:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
```
4. Acceder : `https://portainer.<DOMAINE>` — creer le compte admin.
## Yacht
1. DNS A `yacht` -> `<IP>`
2. Sous-domaine ISPConfig avec proxy vers `http://localhost:8061/`
3. Installer :
```bash
docker volume create yacht_data
docker run -d -p 8061:8000 --name=yacht -v /var/run/docker.sock:/var/run/docker.sock --restart=always -v yacht_data:/config selfhostedpro/yacht
```
4. Login par defaut : `admin@yacht.local` / `pass` — changer immediatement.
## Modele Apache Directives pour proxy Docker
Pour tous les services Docker accessibles via sous-domaine :
```apache
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyRequests Off
ProxyPass /stats !
ProxyPass /.well-known/acme-challenge !
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
ProxyPreserveHost On
ProxyPass / http://localhost:<PORT>/
ProxyPassReverse / http://localhost:<PORT>/
RedirectMatch ^/$ https://<SOUS_DOMAINE>.<DOMAINE>
```
> **Piege :** Apres creation du sous-domaine, supprimer le fichier `standard_index.html` si la page par defaut ISPConfig s'affiche. Aussi verifier que SSL/Let's Encrypt est bien coche.

93
10-services-docker.md Normal file
View File

@@ -0,0 +1,93 @@
# 10. Services Docker
## Wireguard (VPN)
1. DNS A `wireguard` -> `<IP>`
2. Sous-domaine ISPConfig avec proxy vers `http://localhost:51821/`
3. Ouvrir port 51820/udp dans firewall ISPConfig
4. Generer le hash du mot de passe :
```bash
docker run --rm python:3-alpine sh -c "pip install bcrypt -q && python3 -c \"import bcrypt; print(bcrypt.hashpw(b'<MOT_DE_PASSE>', bcrypt.gensalt()).decode())\""
```
5. Installer (en une ligne, remplacer le hash) :
```bash
docker run -d --name=wg-easy -e LANG=fr -e WG_HOST=<IP> -e "PASSWORD_HASH=<HASH_BCRYPT>" -e PORT=51821 -e WG_PORT=51820 -v /etc/wg-easy:/etc/wireguard -p 51820:51820/udp -p 51821:51821/tcp --cap-add=NET_ADMIN --cap-add=SYS_MODULE --sysctl="net.ipv4.conf.all.src_valid_mark=1" --sysctl="net.ipv4.ip_forward=1" --restart unless-stopped ghcr.io/wg-easy/wg-easy
```
> **Piege :** Les versions recentes de wg-easy exigent `PASSWORD_HASH` (bcrypt) au lieu de `PASSWORD`.
## Vaultwarden (gestionnaire de mots de passe)
1. DNS A `vaultwarden` -> `<IP>`
2. Sous-domaine ISPConfig avec proxy vers `http://localhost:1280/`
3. Generer le hash admin :
```bash
echo -n "<MOT_DE_PASSE>" | argon2 "$(openssl rand -base64 32)" -e -id -k 19456 -t 2 -p 1
```
4. Installer (echapper les `$` du hash avec `\$`) :
```bash
docker volume create vaultwarden_data
docker run -d -p 1280:80 --name=vaultwarden --restart=always -v vaultwarden_data:/data:rw -e ROCKET_ENV=staging -e ROCKET_PORT=80 -e ROCKET_WORKERS=10 -e SMTP_HOST=127.0.0.1 -e SMTP_FROM=vaultwarden@<DOMAINE> -e SMTP_PORT=25 -e SMTP_SECURITY=off -e WEBSOCKET_ENABLED=true -e "ADMIN_TOKEN=<HASH_ARGON2>" -e SIGNUPS_ALLOWED=false -e DOMAIN=https://vaultwarden.<DOMAINE> vaultwarden/server:latest
```
5. Activer temporairement les inscriptions via `/admin`, creer son compte, desactiver.
## Heimdall (dashboard)
1. DNS A `heimdall` -> `<IP>`
2. Sous-domaine ISPConfig avec proxy HTTPS vers `https://localhost:1281/`
```apache
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
SSLProxyEngine On
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyPass / https://localhost:1281/
ProxyPassReverse / https://localhost:1281/
```
3. Installer :
```bash
docker volume create heimdall_data
docker run -d -p 1281:443 --name=heimdall --restart=always -v heimdall_data:/config:rw -e PGID=1000 -e PUID=1000 linuxserver/heimdall
```
## Guacamole (bureau a distance)
1. DNS A `guacamole` -> `<IP>`
2. Creer base de donnees `guacamole` dans ISPConfig
3. Sous-domaine ISPConfig avec proxy :
```apache
ProxyPass /guacamole http://localhost:8085/guacamole
ProxyPassReverse /guacamole http://localhost:8085/guacamole
RedirectMatch ^/$ https://guacamole.<DOMAINE>/guacamole
```
4. Installer :
```bash
docker run -d --name guacamole-guacd --restart=always guacamole/guacd
docker run -d --name guacamole-web --restart=always --link guacamole-guacd:guacd -e MYSQL_HOSTNAME=172.17.0.1 -e MYSQL_PORT=3306 -e MYSQL_DATABASE=<DB_NAME> -e MYSQL_USER=<DB_USER> -e MYSQL_PASSWORD=<DB_PASS> -p 8085:8080 guacamole/guacamole
```
5. Importer le schema :
```bash
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql | mysql -u root <DB_NAME>
```
6. Autoriser l'acces depuis Docker :
```bash
mysql -u root -e "GRANT ALL PRIVILEGES ON <DB_NAME>.* TO '<DB_USER>'@'172.17.0.%' IDENTIFIED BY '<DB_PASS>'; FLUSH PRIVILEGES;"
```
7. Login par defaut : `guacadmin` / `guacadmin` — creer un admin et supprimer guacadmin.
> **Piege :** Tomcat 10 natif est incompatible avec Guacamole 1.5.5. Utiliser Docker a la place.

115
11-applications.md Normal file
View File

@@ -0,0 +1,115 @@
# 11. Applications Web
## Wordpress
1. DNS A `wordpress` -> `<IP>`
2. Sous-domaine ISPConfig `wordpress.<DOMAINE>` (SSL, LE, PHP-FPM, HTTPS redirect)
3. Creer base de donnees `wordpress` (user + database dans ISPConfig)
4. Identifier le proprietaire :
```bash
ls -la /var/www/wordpress.<DOMAINE>/ | head -5
# Noter webX:clientY
```
5. Installer :
```bash
cd /tmp
wget -O wordpress.tar.gz https://wordpress.org/latest.tar.gz
tar -xzf wordpress.tar.gz
mv wordpress/* /var/www/wordpress.<DOMAINE>/wordpress/
rm wordpress.tar.gz && rm -rf wordpress
chown -R webX:clientY /var/www/wordpress.<DOMAINE>/wordpress/
```
6. Acceder : `https://wordpress.<DOMAINE>` et suivre l'assistant.
> **Piege :** Si la page par defaut ISPConfig s'affiche, verifier que SSL/LE est coche. Supprimer `standard_index.html` si present.
## Nextcloud
1. Installer les prerequis PHP :
```bash
apt install php-cgi php-curl
```
2. Modifier `/etc/php/8.3/fpm/php.ini` :
```ini
memory_limit = 512M
upload_max_filesize = 500M
post_max_size = 500M
max_execution_time = 300
```
3. DNS A `nextcloud` -> `<IP>`
4. Sous-domaine ISPConfig (SSL, LE, PHP-FPM, HTTPS redirect, Webstatistics: None)
5. Creer base de donnees `nextcloud`
6. Telecharger l'installeur :
```bash
wget -O /var/www/nextcloud.<DOMAINE>/nextcloud/setup-nextcloud.php https://download.nextcloud.com/server/installer/setup-nextcloud.php
chown webX:clientY /var/www/nextcloud.<DOMAINE>/nextcloud/setup-nextcloud.php
```
7. Acceder : `https://nextcloud.<DOMAINE>/setup-nextcloud.php`
- Repertoire : `.`
- Choisir MariaDB, renseigner la base
## Gitea
1. DNS A `gitea` -> `<IP>`
2. Sous-domaine ISPConfig avec proxy vers `http://localhost:3000/`
3. Creer base de donnees `gitea`
4. Installer :
```bash
# Creer l'utilisateur
adduser --system --disabled-password --group --shell /bin/bash --home /home/gitea gitea
# Repertoires
mkdir -p /var/lib/gitea/{data,log} /etc/gitea /run/gitea
chown -R gitea:gitea /var/lib/gitea /run/gitea
chown -R root:gitea /etc/gitea
chmod -R 750 /var/lib/gitea
chmod 770 /etc/gitea
# Telecharger (derniere version)
VERSION=$(wget -qO- https://api.github.com/repos/go-gitea/gitea/releases/latest | grep tag_name | cut -d'"' -f4 | tr -d v)
wget "https://dl.gitea.com/gitea/${VERSION}/gitea-${VERSION}-linux-amd64" -O /usr/local/bin/gitea
chmod 755 /usr/local/bin/gitea
```
5. Creer `/etc/systemd/system/gitea.service` :
```ini
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
Requires=mysqld.service
[Service]
Type=simple
User=gitea
Group=gitea
WorkingDirectory=/var/lib/gitea/
RuntimeDirectory=gitea
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini
Restart=always
Environment=USER=gitea HOME=/home/gitea GITEA_WORK_DIR=/var/lib/gitea
[Install]
WantedBy=multi-user.target
```
```bash
systemctl daemon-reload
systemctl enable gitea.service
systemctl start gitea.service
```
6. Acceder : `https://gitea.<DOMAINE>/install` et configurer.
7. Securiser apres installation :
```bash
chmod 750 /etc/gitea
chown root:gitea /etc/gitea/app.ini
chmod 640 /etc/gitea/app.ini
systemctl restart gitea
```

100
12-backup.md Normal file
View File

@@ -0,0 +1,100 @@
# 12. Backup Rsync
## Prerequis
- Serveur de stockage distant avec acces SSH
- Cle SSH configuree pour l'acces sans mot de passe
## Configurer l'acces SSH
```bash
# Copier la cle SSH de l'utilisateur vers root (le script tourne en root via cron)
mkdir -p /root/.ssh
cp /home/<USER>/.ssh/id_* /root/.ssh/
cp /home/<USER>/.ssh/known_hosts /root/.ssh/
```
Tester :
```bash
ssh -p <PORT_SSH_DISTANT> <USER_DISTANT>@<HOST_DISTANT> "echo OK"
```
## Creer la config
Creer `/etc/vps-backup.env` :
```bash
REMOTE_USER=<USER_DISTANT>
REMOTE_HOST=<HOST_DISTANT>
REMOTE_PORT=<PORT_SSH_DISTANT>
REMOTE_BASE=<CHEMIN_DISTANT>/backups
DB_BACKUP_DIR=/tmp/vps-db-backup
```
```bash
chmod 600 /etc/vps-backup.env
```
## Creer les repertoires distants
```bash
ssh -p <PORT_SSH_DISTANT> <USER_DISTANT>@<HOST_DISTANT> "mkdir -p <CHEMIN_DISTANT>/backups/{db,etc,ispconfig,www}"
```
## Script de backup
Creer `/usr/local/bin/vps-backup.sh` :
```bash
#!/bin/bash
source /etc/vps-backup.env
DATE=$(date +%Y%m%d_%H%M%S)
LOG="/var/log/vps-backup.log"
echo "[$DATE] Backup started" >> $LOG
# Dump databases
mkdir -p $DB_BACKUP_DIR
rm -f $DB_BACKUP_DIR/*.sql.gz $DB_BACKUP_DIR/*.tar.gz
for DB in $(mysql -N -e "SHOW DATABASES" | grep -v -E "^(information_schema|performance_schema|sys)$"); do
mysqldump --single-transaction --routines --triggers "$DB" | gzip > "$DB_BACKUP_DIR/${DB}.sql.gz"
done
# Compresser en tar
tar -czf "$DB_BACKUP_DIR/all-databases-${DATE}.tar.gz" -C $DB_BACKUP_DIR --exclude="*.tar.gz" . || true
rm -f $DB_BACKUP_DIR/*.sql.gz
# Sync
rsync -avz -e "ssh -p $REMOTE_PORT" $DB_BACKUP_DIR/*.tar.gz $REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE/db/ || echo "[$DATE] DB sync failed" >> $LOG
rsync -avz --delete -e "ssh -p $REMOTE_PORT" /etc/ $REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE/etc/ || echo "[$DATE] etc sync failed" >> $LOG
rsync -avz --delete -e "ssh -p $REMOTE_PORT" /usr/local/ispconfig/ $REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE/ispconfig/ || echo "[$DATE] ispconfig sync failed" >> $LOG
rsync -avz --delete -e "ssh -p $REMOTE_PORT" /var/www/ $REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE/www/ || echo "[$DATE] www sync failed" >> $LOG
rm -rf $DB_BACKUP_DIR
DATE_END=$(date +%Y%m%d_%H%M%S)
echo "[$DATE_END] Backup completed" >> $LOG
```
```bash
chmod 755 /usr/local/bin/vps-backup.sh
```
## Cron quotidien
```bash
crontab -e
# Ajouter :
0 2 * * * /usr/local/bin/vps-backup.sh
```
## Tester
```bash
sudo /usr/local/bin/vps-backup.sh
```
> **Piege :** Le script tourne en root via cron. La cle SSH de root doit etre configuree pour l'acces distant.

122
13-securite.md Normal file
View File

@@ -0,0 +1,122 @@
# 13. Securite
## Certificats Let's Encrypt pour les outils
### ISPConfig
Les certificats sont dans `/var/www/clients/clientX/webY/ssl/<DOMAINE>-le.crt` et `.key`.
```bash
SSL_DIR="/var/www/clients/client1/web7/ssl"
ISP_SSL="/usr/local/ispconfig/interface/ssl"
cp $SSL_DIR/<DOMAINE>-le.crt $ISP_SSL/ispserver.crt
cp $SSL_DIR/<DOMAINE>-le.key $ISP_SSL/ispserver.key
# Creer PEM (cert + key)
cat $ISP_SSL/ispserver.crt $ISP_SSL/ispserver.key > $ISP_SSL/ispserver.pem
systemctl restart apache2
```
### Postfix / Dovecot
Les certificats sont automatiquement utilises via le PEM ISPConfig. Pour le SNI multi-domaines, voir [08-sni-mail.md](08-sni-mail.md).
## phpMyAdmin securise
### Changer l'URL et ajouter HTTP Auth
1. Desactiver l'alias global :
```bash
a2disconf phpmyadmin
```
2. DNS A `dbmanage` -> `<IP>`
3. Sous-domaine ISPConfig `dbmanage.<DOMAINE>` (SSL, LE, PHP-FPM, HTTPS redirect)
4. Apache Directives :
```apache
Alias / /usr/share/phpmyadmin/
<Directory /usr/share/phpmyadmin>
Options SymLinksIfOwnerMatch
DirectoryIndex index.php
AuthType Basic
AuthName "Database Management - Restricted Access"
AuthUserFile /etc/phpmyadmin/htpasswd.setup
Require valid-user
<IfModule mod_php.c>
php_admin_value upload_tmp_dir /var/lib/phpmyadmin/tmp
php_admin_value open_basedir /usr/share/phpmyadmin/:/etc/phpmyadmin/:/var/lib/phpmyadmin/:/usr/share/php/:/usr/share/javascript/
</IfModule>
</Directory>
<Directory /usr/share/phpmyadmin/setup>
Require all denied
</Directory>
<Directory /usr/share/phpmyadmin/libraries>
Require all denied
</Directory>
<Directory /usr/share/phpmyadmin/templates>
Require all denied
</Directory>
```
5. Creer le mot de passe HTTP Auth :
```bash
htpasswd -c /etc/phpmyadmin/htpasswd.setup admin
```
### Fail2ban pour phpMyAdmin
Creer `/etc/fail2ban/filter.d/phpmyadmin.conf` :
```
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*/dbmanage.*
user denied.*client: <HOST>
ignoreregex =
```
Creer `/etc/fail2ban/jail.d/phpmyadmin.conf` :
```
[phpmyadmin]
enabled = true
port = http,https
filter = phpmyadmin
logpath = /var/log/apache2/access.log
maxretry = 5
bantime = 3600
findtime = 600
```
```bash
systemctl restart fail2ban
```
### Creer un admin DB
```bash
mysql -u root -e "CREATE USER 'dbadmin'@'localhost' IDENTIFIED BY '<MOT_DE_PASSE>'; GRANT ALL PRIVILEGES ON *.* TO 'dbadmin'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES;"
```
## DNSSEC
### Activer dans ISPConfig
DNS > Zones > `<DOMAINE>` > Zone settings > Sign Zone (DNSSEC) > Save
Recuperer les DS-Data affiches.
### Ajouter chez le registrar
**OVH :** DS Records > Ajouter
- Key tag, Algorithm 13, Digest type 2 (SHA-256), Digest
> **Piege OVH :** OVH peut retourner "Error while checking DNSKEYS" avec des NS personnalises. Retenter ou contacter le support.
**MTN (.ci) :** Envoyer les DS records au support car l'interface bug.

86
14-deploiement-symfony.md Normal file
View File

@@ -0,0 +1,86 @@
# 14. Deploiement Symfony
## Creer le site dans ISPConfig
1. DNS A `<PROJET>` -> `<IP>` (ou zone DNS dediee)
2. Site web ISPConfig : `<PROJET_DOMAINE>` (SSL, LE, PHP-FPM, HTTPS redirect)
3. Creer base de donnees dans ISPConfig
## Apache Directives pour Symfony
Dans l'onglet Options du site :
```apache
DocumentRoot /var/www/<PROJET_DOMAINE>/web/public
<Directory /var/www/<PROJET_DOMAINE>/web/public>
AllowOverride All
Require all granted
FallbackResource /index.php
</Directory>
```
## Lien symbolique
```bash
ln -s /var/www/clients/clientX/webY/web /var/www/<PROJET>
```
## Permissions
```bash
# Identifier le proprietaire
ls -la /var/www/<PROJET_DOMAINE>/ | head -5
# Noter webX:clientY
# Ajouter votre user au groupe client
usermod -a -G clientY <USER>
# Donner l'acces groupe
chmod 750 /var/www/clients/clientX/webY/web
# ACL pour acces complet
apt install acl
setfacl -R -m u:<USER>:rwx /var/www/clients/clientX/webY/web
setfacl -R -d -m u:<USER>:rwx /var/www/clients/clientX/webY/web
```
> **Important :** Apres connexion SSH, executer `newgrp clientY` pour activer le groupe.
## Cloner le projet
```bash
git clone git@github.com:<REPO>.git /tmp/<PROJET>
cp -r /tmp/<PROJET>/. /var/www/clients/clientX/webY/web/
chown -R webX:clientY /var/www/clients/clientX/webY/web/
rm -rf /tmp/<PROJET>
```
## Installer les dependances
```bash
cd /var/www/<PROJET>
composer install
```
## Configuration .env
```bash
# Base de donnees
DATABASE_URL="mysql://<DB_USER>:<DB_PASS>@localhost:3306/<DB_NAME>"
# Mail (Postfix local)
MAILER_DSN=smtp://127.0.0.1:25?auto_tls=false
```
## Migrations
```bash
php bin/console doctrine:migrations:migrate --no-interaction
```
## Cache
```bash
php bin/console cache:clear
```

109
15-livekit.md Normal file
View File

@@ -0,0 +1,109 @@
# 15. LiveKit (Teleconsultation Video)
## Prerequis
- Docker installe
- Sous-domaine pour LiveKit (ex: `video.<PROJET_DOMAINE>`)
- Certificats SSL
## DNS et sous-domaine
1. DNS A `video` -> `<IP>` (dans la zone du projet)
2. Sous-domaine ISPConfig `video.<PROJET_DOMAINE>` (SSL, LE, PHP-FPM)
## Ports firewall
ISPConfig > System > Firewall, ajouter :
- TCP : `7880,7881,5349`
- UDP : `7882,3478`
## Recuperer les certificats
```bash
# Trouver les certificats generes par ISPConfig
find /var/www/clients/ -name "video.<PROJET_DOMAINE>-le.*"
# Copier
mkdir -p /chemin/projet/docker/livekit/certs
cp /var/www/clients/clientX/webY/ssl/video.<PROJET_DOMAINE>-le.crt /chemin/projet/docker/livekit/certs/fullchain.pem
cp /var/www/clients/clientX/webY/ssl/video.<PROJET_DOMAINE>-le.key /chemin/projet/docker/livekit/certs/privkey.pem
chown -R <USER>:<USER> /chemin/projet/docker/livekit/certs/
```
> **Piege :** Verifier que la cle privee correspond au certificat :
> ```bash
> openssl x509 -noout -pubkey -in certs/fullchain.pem | md5sum
> openssl ec -pubout -in certs/privkey.pem 2>/dev/null | md5sum
> # Les deux md5 doivent etre identiques
> ```
## Configuration
### .env
```bash
LIVEKIT_API_KEY=<generer avec: openssl rand -hex 16>
LIVEKIT_API_SECRET=<generer avec: openssl rand -base64 32>
TZ=Africa/Abidjan
LIVEKIT_CPU_LIMIT=2.0
LIVEKIT_MEM_LIMIT=2G
```
### livekit-prod.yaml
```yaml
port: 7880
redis:
address: localhost:6380 # Port different du Redis systeme (6379)
rtc:
udp_port: 7882
tcp_port: 7881
allow_tcp_fallback: true
use_external_ip: false
node_ip: <IP>
turn:
enabled: true
tls_port: 5349
udp_port: 3478
domain: video.<PROJET_DOMAINE>
cert_file: /etc/livekit/tls/fullchain.pem
key_file: /etc/livekit/tls/privkey.pem
room:
auto_create: true
empty_timeout: 300
max_participants: 2
webhook:
api_key: <LIVEKIT_API_KEY>
urls:
- https://<PROJET_DOMAINE>/api/v1/teleconsultation/livekit-webhook
```
> **Piege :** Le Redis du container doit tourner sur un port different (6380) du Redis systeme (6379) quand on utilise `network_mode: host`.
## Demarrer
```bash
cd /chemin/projet/docker/livekit
docker compose -f docker-compose.prod.yml up -d
```
## Verifier
```bash
docker logs djeliba_livekit_server --tail 10
# Chercher "starting LiveKit server" et "Starting TURN server"
```
## Symfony .env
```
TELECONSULTATION_PROVIDER=livekit
LIVEKIT_URL=wss://video.<PROJET_DOMAINE>:7880
LIVEKIT_API_KEY=<meme valeur>
LIVEKIT_API_SECRET=<meme valeur>
```

109
16-notes-pieges.md Normal file
View File

@@ -0,0 +1,109 @@
# 16. Notes et Pieges
## Pieges frequents
### UFW vs ISPConfig
Ne jamais utiliser UFW avec ISPConfig. ISPConfig gere le firewall via iptables. Desactiver UFW : `ufw disable`.
### Ports bloques par l'hebergeur
Contabo bloque certains ports non-standard au niveau de son firewall externe. Toujours tester l'acces depuis l'exterieur apres ouverture d'un port.
### Page "Welcome to your website" ISPConfig
Apres creation d'un sous-domaine, la page par defaut ISPConfig peut s'afficher. Solutions :
1. Verifier que SSL/Let's Encrypt est bien coche
2. Supprimer `standard_index.html` : `find /var/www/ -path "*<sous-domaine>*standard_index*" -delete`
### DNS Templates : NS personnalises
Les templates DNS doivent pointer les NS vers le domaine serveur principal (ex: `ns1.z-ana.com`) et non `ns1.{DOMAIN}`. Sinon les domaines heberges auront des problemes de delegation.
### Domaines .ci chez MTN
- Les glue records vers le meme domaine ne fonctionnent pas dans l'interface
- Solution : pointer les NS vers le domaine principal du serveur
- Le support est lent — prevoir des delais
### Dovecot SNI
Le SNI doit etre configure dans `dovecot.conf` principal, pas dans `conf.d/10-ssl.conf`. ISPConfig ecrase les fichiers `conf.d`.
### Redis conflit de ports
Si vous installez un service Docker avec Redis en `network_mode: host`, utiliser un port different (ex: 6380) pour eviter le conflit avec le Redis systeme (6379).
### Guacamole et Tomcat 10
Guacamole 1.5.5 n'est pas compatible avec Tomcat 10 (Ubuntu 24.04). Utiliser Docker a la place.
### wg-easy PASSWORD vs PASSWORD_HASH
Les versions recentes de wg-easy exigent un hash bcrypt (`PASSWORD_HASH`) au lieu du mot de passe en clair (`PASSWORD`).
### MAILER_DSN Symfony
Pour envoyer des mails via Postfix local : `smtp://127.0.0.1:25?auto_tls=false`. Sans `auto_tls=false`, Symfony tente STARTTLS qui echoue localement.
### Permissions Symfony
Apres connexion SSH, executer `newgrp clientX` pour activer le groupe et acceder au dossier du projet.
### Certificat ISPConfig vs mail
Le certificat dans `ispserver.crt` est utilise pour le panel ISPConfig ET Dovecot/Postfix par defaut. Garder le certificat du domaine principal. Le SNI gere les certificats specifiques par domaine mail.
### Propagation DNS
- OVH : quasi instantanee
- MTN/Cloud4Africa (.ci) : peut prendre des heures
- Utiliser `dig @8.8.8.8 <domaine> A +short` pour verifier
## Ports utilises
| Port | Service | Protocole |
|------|---------|-----------|
| 22/50022 | SSH | TCP |
| 25 | SMTP | TCP |
| 53 | DNS | TCP+UDP |
| 80 | HTTP | TCP |
| 110 | POP3 | TCP |
| 143 | IMAP | TCP |
| 443 | HTTPS | TCP |
| 465 | SMTP SSL | TCP |
| 587 | SMTP submission | TCP |
| 993 | IMAP SSL | TCP |
| 995 | POP3 SSL | TCP |
| 2812 | Monit | TCP |
| 3000 | Gitea | TCP |
| 3100 | Grafana | TCP |
| 3101 | Loki | TCP |
| 3306 | MariaDB | TCP |
| 3478 | TURN UDP | UDP |
| 5349 | TURN TLS | TCP |
| 6379 | Redis systeme | TCP |
| 6380 | Redis LiveKit | TCP |
| 7880 | LiveKit signal | TCP |
| 7881 | LiveKit TCP | TCP |
| 7882 | LiveKit UDP | UDP |
| 8061 | Yacht | TCP |
| 8080 | ISPConfig | TCP |
| 8081 | ISPConfig apps | TCP |
| 8085 | Guacamole | TCP |
| 9050 | Portainer | TCP |
| 9080 | Promtail | TCP |
| 9090 | Prometheus | TCP |
| 10000 | Webmin | TCP |
| 51820 | Wireguard | UDP |
| 51821 | wg-easy interface | TCP |
| 1280 | Vaultwarden | TCP |
| 1281 | Heimdall | TCP |
## Architecture des sous-domaines
| Sous-domaine | Service | Proxy vers |
|-------------|---------|-----------|
| mail.* | Roundcube | localhost:8080/webmail/ |
| rspamd.* | Rspamd | localhost:8081/rspamd/ |
| autoconfig.* | Config mail auto | Fichiers XML directs |
| autodiscover.* | Config Outlook | Fichiers XML directs |
| webmin.* | Webmin | localhost:10000 |
| portainer.* | Portainer | localhost:9050 |
| yacht.* | Yacht | localhost:8061 |
| grafana.* | Grafana | localhost:3100 |
| wireguard.* | Wireguard | localhost:51821 |
| vaultwarden.* | Vaultwarden | localhost:1280 |
| heimdall.* | Heimdall | localhost:1281 (HTTPS) |
| guacamole.* | Guacamole | localhost:8085/guacamole |
| dbmanage.* | phpMyAdmin | Direct (Alias) |
| wordpress.* | Wordpress | Direct |
| nextcloud.* | Nextcloud | Direct |
| gitea.* | Gitea | localhost:3000 |

52
README.md Normal file
View File

@@ -0,0 +1,52 @@
# Guide d'Installation VPS Complet
Guide pas-a-pas pour configurer un serveur VPS de zero avec panel de gestion, mail, Docker, monitoring et services.
## Variables a personnaliser
Avant de commencer, notez vos valeurs :
| Variable | Exemple | Votre valeur |
|----------|---------|-------------|
| `<IP>` | 62.169.29.111 | |
| `<IPV6>` | 2a02:c207:2316:3066::1 | |
| `<DOMAINE>` | z-ana.com | |
| `<HOSTNAME>` | mail | |
| `<FQDN>` | mail.z-ana.com | |
| `<USER>` | scriptshadow | |
| `<SSH_PORT>` | 50022 | |
| `<EMAIL>` | admin@z-ana.com | |
## Sommaire
1. [Prerequis et choix](01-prerequis.md) - Hebergeur, registrar, OS
2. [Configuration de base](02-config-base.md) - Hostname, apt, locale, swap, MOTD
3. [ISPConfig](03-ispconfig.md) - Installation et configuration
4. [HestiaCP (Alternative)](03-bis-hestiacp.md) - Alternative a ISPConfig
5. [DNS](04-dns.md) - Templates, zones, glue records
6. [Webmin](05-webmin.md) - Administration systeme
7. [Monitoring](06-monitoring.md) - Munin, Monit, Grafana, Prometheus, Loki
8. [Mail](07-mail.md) - Rspamd, DKIM, DMARC, Roundcube, autoconfig
9. [SNI Mail](08-sni-mail.md) - Certificats multi-domaines
10. [Docker](09-docker.md) - Docker, Swarm, Portainer, Yacht
11. [Services Docker](10-services-docker.md) - Wireguard, Vaultwarden, Heimdall, Guacamole
12. [Applications](11-applications.md) - Wordpress, Nextcloud, Gitea
13. [Backup](12-backup.md) - Script rsync quotidien
14. [Securite](13-securite.md) - Certificats LE, phpMyAdmin, Fail2ban, DNSSEC
15. [Deploiement Symfony](14-deploiement-symfony.md) - Projet Symfony sur Apache
16. [LiveKit](15-livekit.md) - Teleconsultation video
17. [Notes et pieges](16-notes-pieges.md) - Lecons apprises
## Temps estime
- Configuration de base + ISPConfig : ~2h
- Mail complet : ~1h
- Docker + services : ~2h
- Monitoring : ~1h
- Total : ~6-8h pour un serveur complet
## Prerequis
- VPS Ubuntu 24.04 (Contabo ou equivalent)
- Domaine chez OVH (recommande) ou autre registrar
- Acces root au VPS