Distribuzione
Come eseguire NexoSaaS: stack Docker, reverse proxy host, dominio di base e TLS.
Cosa stai distribuendo
| 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 |
I siti NexoPOS dei clienti non sono servizi Compose separati. L’agente scrive i file in HOST_AGENT_HOME_BASE e nginx include i suoi vhost.
1. Installazione di Docker
Prerequisiti
- Docker Engine + Docker Compose v2
- Porte libere (predefinite): 8080 (HTTP), 3307 (host MySQL), 6380 (host Redis)
Passaggi
# 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
Gli entrypoint di solito generano APP_KEY e avviano le migrazioni quando configurati. Popola il catalogo + l’amministratore predefinito una volta:
docker compose -f deploy/docker-compose.yml exec app php artisan db:seed --force
Account predefiniti con seed (solo per sviluppo):
| Role | Password | |
|---|---|---|
| Platform admin | [email protected] | password |
| Test user | [email protected] | password |
Apri il control plane: http://localhost:8080 (oppure la tua APP_URL).
Prontezza:
docker compose -f deploy/docker-compose.yml exec app php artisan platform:launch-check
Variabili d’ambiente importanti
I segreti del prodotto (Stripe, SMTP, GitHub PAT, S3, policy del dominio) sono in **Admin → Impostazioni**, non nelle variabili d’ambiente di runtime.
| 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 |
Modalità dell’agente host
| 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 non è di per sé una storia completa di isolamento in produzione multi-tenant. Usa uno script su un VPS quando ti serve una separazione dei tenant di livello production.
2. Metti Nginx davanti allo stack
Forma di produzione consigliata:
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
Esempio host Nginx (piano di controllo)
Sostituisci i nomi host e la porta upstream con i tuoi.
# /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;
}
}
Imposta:
APP_URL=https://app.yourdomain.com
Laravel si fida degli header inoltrati quando è configurato per la tua configurazione proxy; assicurati che l’app veda correttamente HTTPS, così gli URL firmati e i cookie restano sicuri.
Segnaposto per screenshot: Browser aperto sulla schermata di accesso del control plane al tuo URL HTTPS pubblico
Nomi host del tenant
- Docker / local agent: le configurazioni nginx del tenant sono scritte in {HOST_AGENT_HOME_BASE}/.platform/nginx-enabled/*.conf e incluse da nginx di Compose (deploy/docker/nginx/default.conf).
- Browser locale : http://{install-subdomain}.localhost:8080 spesso funziona senza /etc/hosts.
- Produzione: DNS per *.base_domain (e domini personalizzati) deve raggiungere lo stesso edge che può instradare verso il nginx della piattaforma (oppure il nginx del VPS gestito dall’agent dello script).
Se il reverse proxy dell’host inoltra solo app.yourdomain.com, i sottodomini dei tenant devono avere una delle seguenti opzioni:
- lo stesso proxy con un server_name con carattere jolly / oppure con blocchi server separati, o
- esposizione diretta della piattaforma nginx / vhost gestiti dall’agente.
Pianifica DNS e TLS per i tenant insieme al dominio di base (sezione successiva).
3. Dominio di base
Le installazioni ottengono un nome host della piattaforma gratuito:
{slug}.{base_domain}
Esempio: dominio di base saas.example.com → acme-store.saas.example.com.
Configura in Admin
- Accedi come amministratore della piattaforma (2FA fuori sede).
- Apri Amministrazione → Impostazioni → Dominio.
- Imposta:
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 |
Il valore PLATFORM_BASE_DOMAIN in .env imposta solo il valore Admin nelle impostazioni vuote; in runtime usa Admin → Dominio.
4. SSL / Let’s Encrypt
Piano di controllo (reverse proxy host)
Utilizzando Certbot (esempio):
# 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
Usare Caddy spesso è più semplice (HTTPS automatico); reverse_proxy su 127.0.0.1:8080.
Certificati del conduttore
Per la verifica di provisioning e del dominio personalizzato, l’agente host è responsabile della TLS per i nomi host del tenant (flusso in stile Let’s Encrypt sul percorso VPS/agent).
Gli operatori dovrebbero:
- Assicurati che il VPS possa completare la HTTP-01 (o la sfida scelta dall’agente) per i nomi host di installazione.
- Imposta in modo ragionevole le modifiche del dominio verificate al giorno (impostazione predefinita: 3) per evitare che i clienti esauriscano i limiti di velocità di LE.
- Mantieni accurato l’IPv4 pubblico affinché le istruzioni DNS che i clienti vedono siano corrette.
Nota: Docker locale con *.localhost non richiede LE pubbliche per i test UI quotidiani.
Webhook dei pagamenti
I gateway di produzione devono raggiungere endpoint HTTPS, ad esempio:
- https://app.yourdomain.com/webhooks/stripe
- https://app.yourdomain.com/webhooks/paddle
- https://app.yourdomain.com/webhooks/mollie
Configura i segreti di firma in Admin → Impostazioni → Impostazioni di fatturazione.
5. Checklist post-deploy
| 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 |
Comandi operativi utili
# 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