Implantação
Como executar o NexoSaaS: stack Docker, proxy reverso no host, domínio base e TLS.
O que você está implantando
| 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 |
Os sites do cliente NexoPOS não são serviços Compose separados. O agente grava arquivos em HOST_AGENT_HOME_BASE, e o nginx inclui seus vhosts.
1. Instalação do Docker
Pré-requisitos
- Docker Engine + Docker Compose v2
- Portas livres (padrão): 8080 (HTTP), 3307 (host do MySQL), 6380 (host do Redis)
Passos
# 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
Os pontos de entrada normalmente geram APP_KEY e executam migrações quando configurados. Semeie o catálogo + admin padrão uma vez:
docker compose -f deploy/docker-compose.yml exec app php artisan db:seed --force
Contas semeadas padrão (apenas para dev):
| Role | Password | |
|---|---|---|
| Platform admin | [email protected] | password |
| Test user | [email protected] | password |
Abra o plano de controle: http://localhost:8080 (ou seu APP_URL).
Prontidão:
docker compose -f deploy/docker-compose.yml exec app php artisan platform:launch-check
Variáveis de ambiente importantes
Segredos do produto (Stripe, SMTP, GitHub PAT, S3, política de domínio) são de Admin → Configurações, não de variáveis de ambiente em tempo de execução.
| 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 |
Modos do 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. |
A composição não é, por si só, uma história completa de isolamento de produção multi-tenant. Use scripts em um VPS quando precisar de separação de tenants com nível de produção.
2. Hospede o Nginx na frente da stack
Forma de produção recomendada:
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
Exemplo de host Nginx (plano de controle)
Substitua os nomes de host e a porta upstream pelos seus.
# /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;
}
}
Conjunto:
APP_URL=https://app.yourdomain.com
O Laravel confia nos cabeçalhos encaminhados quando configurado para a configuração do seu proxy; garanta que a aplicação veja o HTTPS corretamente para que URLs assinadas e cookies permaneçam seguros.
Espaço reservado do screenshot: navegador aberto na página de login do painel de controle no seu URL HTTPS público
Nomes de host do inquilino
- Docker / agente local: as configurações do nginx do tenant são gravadas em {HOST_AGENT_HOME_BASE}/.platform/nginx-enabled/*.conf e incluídas pelo nginx do Compose (deploy/docker/nginx/default.conf).
- Navegador local: http://{install-subdomain}.localhost:8080 geralmente funciona sem /etc/hosts.
- Produção: O DNS para *.base_domain (e domínios personalizados) deve chegar à mesma borda que consegue rotear para o nginx da plataforma (ou o nginx do VPS gerenciado pelo agente script).
Se o proxy reverso do host encaminhar apenas app.yourdomain.com, os subdomínios do tenant precisam de uma destas opções:
- o mesmo proxy com um server_name com curingas / separe blocos de servidor, ou
- exposição direta da plataforma nginx / vhosts gerenciados pelo agente.
Planeje DNS e TLS para os tenants junto com o domínio base (próxima seção).
3. Domínio base
As instalações recebem um nome de host de plataforma gratuito:
{slug}.{base_domain}
Exemplo: domínio base saas.example.com → acme-store.saas.example.com.
Configurar em Administração
- Entrar como administrador da plataforma (2FA fora do local).
- Abra Admin → Configurações → Domínio.
- Conjunto:
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 |
O PLATFORM_BASE_DOMAIN em .env só define o valor de Admin em configurações vazias; em tempo de execução, usa Admin → Domain.
4. SSL / Let’s Encrypt
Plano de controle (proxy reverso do host)
Usando Certbot (exemplo):
# 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
Usar Caddy é frequentemente mais simples (HTTPS automático); faça reverse_proxy para 127.0.0.1:8080.
Certificados do inquilino
Na provisão e na verificação de domínio personalizado, o agente host é responsável pelo TLS para os nomes de host do tenant (fluxo no estilo Let’s Encrypt no caminho do VPS/agente).
Os operadores devem:
- Garanta que o VPS consiga concluir o HTTP-01 (ou o desafio escolhido pelo agente) para os nomes de host de instalação.
- Defina de forma razoável as alterações de domínio verificadas máximas por dia (padrão 3) para que os clientes não esgotem os limites de taxa do LE.
- Mantenha o IPv4 público preciso para que as instruções de DNS que os clientes veem estejam corretas.
Nota: O Docker local com *.localhost não precisa de LE público para testes de UI do dia a dia.
Webhooks de pagamento
As portas de produção devem alcançar endpoints HTTPS, por exemplo:
- https://app.yourdomain.com/webhooks/stripe
- https://app.yourdomain.com/webhooks/paddle
- https://app.yourdomain.com/webhooks/mollie
Configure segredos de assinatura em Admin → Settings → Billing Settings.
5. Checklist pós-implantação
| 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 |
Comandos úteis de operações
# 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