Déploiement
Comment exécuter NexoSaaS : pile Docker, reverse proxy sur l’hôte, domaine de base et TLS.
Ce que vous déployez
| Component | Role |
|---|---|
| app (PHP-FPM) | Laravel control plane |
| nginx (compose) | Serves control plane + generated tenant vhosts |
| horizon | Queue workers (provision, backups, mail, etc.) |
| scheduler | schedule:work (billing lifecycle, backup waves, …) |
| mysql | Control plane + per-install tenant databases (Docker) |
| redis | Cache, sessions, queues |
| Host agent | Creates tenant paths, nginx snippets, SSL, DBs |
Les sites NexoPOS du client ne sont pas des services Compose distincts. L’agent écrit des fichiers dans HOST_AGENT_HOME_BASE, et nginx inclut ses vhosts.
1. Installation de Docker
Prérequis
- Moteur Docker + Docker Compose v2
- Ports libres (par défaut) : 8080 (HTTP), 3307 (hôte MySQL), 6380 (hôte Redis)
Étapes
# From the repository root
cp deploy/.env.docker.example .env
# Optional: set a stable public URL early (production example)
# APP_URL=https://app.yourdomain.com
# APP_ENV=production
# APP_DEBUG=false
docker compose -f deploy/docker-compose.yml up -d --build
Les points d’entrée de composition génèrent généralement APP_KEY et exécutent les migrations lorsqu’ils sont configurés. Initialisez le catalogue + l’administrateur par défaut une seule fois :
docker compose -f deploy/docker-compose.yml exec app php artisan db:seed --force
Comptes préalimentés par défaut (uniquement pour le développement) :
| Role | Password | |
|---|---|---|
| Platform admin | [email protected] | password |
| Test user | [email protected] | password |
Ouvrez le plan de contrôle : http://localhost:8080 (ou votre APP_URL).
Préparation :
docker compose -f deploy/docker-compose.yml exec app php artisan platform:launch-check
Variables d’environnement importantes
Les secrets du produit (Stripe, SMTP, GitHub PAT, S3, politique de domaine) sont dans **Admin → Paramètres**, pas dans les variables d’environnement d’exécution.
| Variable | Typical Docker | Notes |
|---|---|---|
| APP_URL | http://localhost:8080 | Must match the URL browsers use (payment return URLs) |
| APP_ENV / APP_DEBUG | local / true | Production: production / false |
| PLATFORM_BASE_DOMAIN | localhost | Seed-only default for Admin Domain base_domain |
| HOST_AGENT_DRIVER | local | Docker/CI. Production VPS isolation: script |
| HOST_AGENT_HOME_BASE | /home | Tenant homes + .platform/nginx-enabled |
| HOST_AGENT_LOCAL_REAL_CLONE | false | true = real NexoPOS tarball (needs network + GitHub) |
| HOST_AGENT_TENANT_DB_* | MySQL service | Per-install DB creation in Docker |
| QUEUE_CONNECTION | redis | Required for Horizon |
Modes de l’agent hôte
| Driver | Use when |
|---|---|
| local | Docker / evaluation. Same path layout as production, shared FPM, no real useradd. |
| script | Real Linux VPS: OS users, per-user FPM, system nginx, true isolation. |
Compose n’est pas, à lui seul, une histoire complète d’isolation en production multi-tenant. Utilisez un script sur un VPS lorsque vous avez besoin d’une séparation des locataires de niveau production.
2. Héberger Nginx en amont de la pile
Forme de production recommandée :
Internet
│
▼
Host Nginx / Caddy (TLS termination, :443)
│ proxy_pass → 127.0.0.1:8080
▼
Compose nginx (control plane + tenant includes)
│
▼
Compose app (PHP-FPM) + tenant docroots on volume
Exemple d’hôte Nginx (plan de contrôle)
Remplacez les noms d’hôte et le port upstream par les vôtres.
# /etc/nginx/sites-available/nexosaas-control.conf
server {
listen 80;
server_name app.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name app.yourdomain.com;
# ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem;
client_max_body_size 64M;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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;
proxy_read_timeout 120s;
}
}
Ensemble :
APP_URL=https://app.yourdomain.com
Laravel fait confiance aux en-têtes transmis lorsque votre configuration de proxy le prévoit ; assurez-vous que l’application voit correctement le protocole HTTPS afin que les URL signées et les cookies restent sécurisés.
Espace réservé de capture d’écran : navigateur ouvert sur la connexion du plan de contrôle à votre URL HTTPS publique
Noms d’hôtes des locataires
- Docker / agent local : les configurations nginx du tenant sont écrites sous {HOST_AGENT_HOME_BASE}/.platform/nginx-enabled/*.conf et incluses par le nginx de Compose (deploy/docker/nginx/default.conf).
- Navigateur local : http://{install-subdomain}.localhost:8080 fonctionne souvent sans /etc/hosts.
- Production : le DNS pour *.base_domain (et les domaines personnalisés) doit atteindre le même point de terminaison (edge) capable d’acheminer vers le nginx de la plateforme (ou le nginx du VPS géré par l’agent script).
Si le reverse proxy hôte ne transmet que app.yourdomain.com, les sous-domaines des locataires doivent soit :
- le même proxy avec un server_name de type wildcard / séparer les blocs de serveurs, ou
- Exposition directe de la plateforme nginx / aux hôtes virtuels gérés par l’agent.
Planifier le DNS et le TLS pour les locataires avec le domaine de base (section suivante).
3. Domaine de base
Les installations bénéficient d’un nom d’hôte de plateforme gratuit :
{slug}.{base_domain}
Exemple : domaine de base saas.example.com → acme-store.saas.example.com.
Configurer dans l’administration
- Connectez-vous en tant qu’administrateur de la plateforme (2FA hors du local).
- Ouvrir Admin → Paramètres → Domaine.
- Ensemble :
DNS
| Record | Name | Target |
|---|---|---|
| A | app.yourdomain.com (control plane) | VPS public IP |
| A (or CNAME) | *.saas.example.com | Same IP (or load balancer) |
| Optional AAAA | same hosts | Public IPv6 |
PLATFORM_BASE_DOMAIN dans .env ne renseigne la valeur Admin que lorsque les paramètres sont vides ; à l’exécution, le système utilise Admin → Domain.
4. SSL / Let’s Encrypt
Plan de contrôle (proxy inverse hôte)
En utilisant Certbot (exemple) :
# After DNS for app.yourdomain.com points at the VPS
sudo certbot --nginx -d app.yourdomain.com
# or: certbot certonly --webroot ... then point ssl_certificate paths
L’utilisation de Caddy est souvent plus simple (HTTPS automatique) ; reverse_proxy vers 127.0.0.1:8080.
Certificats du locataire
Lors de la fourniture et de la vérification du domaine personnalisé, l’agent hôte est responsable du TLS pour les noms d’hôte des locataires (flux de type Let’s Encrypt sur le chemin VPS / agent).
Les opérateurs doivent :
- Assurez-vous que le VPS peut terminer l’HTTP-01 (ou le défi choisi par l’agent) pour les noms d’hôte d’installation.
- Définissez raisonnablement le nombre maximal de modifications de domaine vérifié par jour (par défaut : 3) afin d’éviter que les clients n’épuisent les limites de taux LE.
- Conservez l’exactitude de l’IPv4 publique afin que les instructions DNS que les clients voient soient correctes.
Remarque : un Docker local avec *.localhost n’a pas besoin de LE public pour les tests d’interface utilisateur au quotidien.
Webhooks de paiement
Les passerelles de production doivent atteindre des points de terminaison HTTPS, par exemple :
- https://app.yourdomain.com/webhooks/stripe
- https://app.yourdomain.com/webhooks/paddle
- https://app.yourdomain.com/webhooks/mollie
Configurez les secrets de signature sous Admin → Paramètres → Paramètres de facturation.
5. Liste de contrôle post-déploiement
| Step | Command / action |
|---|---|
| Stack healthy | docker compose -f deploy/docker-compose.yml ps |
| Seed catalog / admin (once) | exec app php artisan db:seed --force |
| Launch check | exec app php artisan platform:launch-check |
| Horizon running | Compose horizon service Up |
| Scheduler running | Compose scheduler service Up |
| First admin usable | Verify email + 2FA |
| Product config | SMTP, payments, GitHub, S3, domain |
| Fake payments | Not allowed in production launch-check |
Commandes d’opérations utiles
# Shell into app
docker compose -f deploy/docker-compose.yml exec app bash
# Logs
docker compose -f deploy/docker-compose.yml logs -f app horizon nginx
# Rebuild frontend assets
docker compose -f deploy/docker-compose.yml run --rm -e DOCKER_FORCE_BUILD_ASSETS=true assets
# Wipe evaluation installs (keeps users/catalog/settings)
docker compose -f deploy/docker-compose.yml exec app \
php artisan platform:reset-evaluation --force