Guias · Publicação

Instalação em servidor próprio

Publique o sistema num servidor Linux seu, pela tela Deploy SSH. Você prepara a máquina com um comando, o MadBuilder envia o app pela conexão SSH e o assistente /install do próprio sistema termina o trabalho: banco, usuário administrador e configuração.

Linux · Ubuntu 22.04/24.04/26.04 · Debian 12 Apache + mod_php PHP 8.4.1+ 64-bit Acesso root
01

Antes de começar

Você vai precisar de:

  • Um servidor Linux (VPS ou máquina física) em Ubuntu 22.04 / 24.04 ou Debian 12, 64-bit, com acesso root ou sudo.
  • A porta 22 (SSH) acessível a partir do MadBuilder — pode ser restrita ao IP do builder.
  • As portas 80 e 443 abertas para quem vai usar o sistema.
  • Opcional: um domínio apontando para o servidor. Com ele o script emite HTTPS pelo Let's Encrypt; sem domínio, ou sem DNS público (intranet, .test, .local), gera um certificado autoassinado (no IP ou no domínio) — o site fica em HTTPS e o navegador avisa uma vez. HTTPS não é opcional: o app gerado roda em produção com cookie de sessão Secure; em HTTP puro a sessão não volta e o /install responde 419. O script redireciona a porta 80 para 443.
O que não é suportado. Servidores Windows e macOS (o deploy usa bash, tar e unzip); hospedagem compartilhada sem SSH ou sem root; PHP abaixo de 8.4.1 ou builds 32-bit (o app dá erro 500 em toda página); distribuições fora da lista — CentOS, Alpine e similares não foram testadas. No Ubuntu 26.04 o script usa o PHP 8.5 nativo da distribuição (o ppa:ondrej/php não publica pacotes para ele, então --php 8.4 é recusado). O script configura Apache; quem prefere nginx faz a configuração à mão (veja as perguntas frequentes).
02

Passo 1 — Provisionar o servidor

Conecte no servidor como root (ou um usuário com sudo) e execute o instalador. Ele instala PHP, Apache, as extensões e as ferramentas que o deploy precisa, cria o usuário de deploy e o diretório do sistema com as permissões certas.

curl -fsSL https://api.madbuilder.dev/install.sh | sudo bash -s -- provision --path /var/www/erp --user deploy

A tela Deploy SSH gera esse comando já preenchido: na seção Requisitos do servidor, clique em Ver comando de provisionamento. Ele vem com o caminho, o usuário e a chave pública do builder do servidor selecionado.

Prefere ler o script antes de rodar? Baixe, inspecione e execute:

curl -fsSLo madbuilder-server.sh https://api.madbuilder.dev/install.sh && less madbuilder-server.sh && sudo bash madbuilder-server.sh provision --path /var/www/erp --user deploy

Opções do script

O mesmo arquivo tem dois subcomandos: provision (root; instala e configura) e check (sem root; só confere e reporta). É o check que o MadBuilder executa pela conexão SSH quando você clica em Verificar requisitos.

OpçãocheckprovisionPadrão · o que faz
--path <dir>obrigatórioobrigatórioRaiz do sistema. O Apache aponta para <path>/public.
--user <nome>opcionalobrigatórioUsuário SSH de deploy. Criado com useradd -m se não existir.
--group <nome>opcionalopcionalwww-data. Grupo do servidor web, dono do diretório junto com o usuário.
--php 8.4|8.5—opcionalSem a flag o script escolhe: 8.4 no Ubuntu 22.04/24.04 e Debian 12, 8.5 no Ubuntu 26.04 (único disponível lá). Fica como PHP padrão do sistema.
--db pgsql|mysql|none—opcionalnone. Instala um banco local e cria o usuário administrador madbuilder_admin.
--domain <fqdn>—opcionalDefine o ServerName do VirtualHost e liga o HTTPS (veja --ssl).
--ssl auto|letsencrypt|
self-signed|none
—opcionalauto: com --domain tenta Let's Encrypt e, se não emitir, cai no autoassinado; sem --domain, autoassinado no IP. self-signed pula o certbot. none: só HTTP — o app não funciona assim em produção (cookie Secure → 419).
--email <addr>—opcionalE-mail de contato do certbot (avisos de renovação).
--authorized-key '<chave>'—opcionalChave pública instalada em ~<user>/.ssh/authorized_keys. A tela já inclui a chave do builder.
--no-cron · --no-queue
--no-swap · --no-certbot
—opcionalPula a etapa correspondente (--no-certbot = --ssl none).
--yes—opcionalNão pede confirmação. Útil em automação.
--dry-run—opcionalMostra o que faria, sem alterar nada.
--machineopcional—Saída em linhas legíveis por máquina (é o que o MadBuilder lê).
--only os,tools,perms,webrootopcional—Restringe a verificação a alguns grupos.

Códigos de saída: 0 pronto / concluído · 1 alguma verificação ou etapa falhou · 2 uso incorreto, sem root ou distribuição não suportada.

O que o provision faz

  1. Valida a distribuição (Ubuntu 22.04/24.04/26.04, Debian 12) e o acesso root, e fecha a versão do PHP — no Ubuntu 26.04 só existe 8.5, então --php 8.4 é recusado antes de instalar qualquer coisa.
  2. Mostra o plano e pede confirmação. --yes pula essa pergunta.
  3. Pacotes base via apt: ca-certificates curl gnupg unzip tar gzip cron acl.
  4. Repositório do PHP: ppa:ondrej/php no Ubuntu 22.04/24.04, packages.sury.org no Debian 12; no Ubuntu 26.04 nenhum — o PHP 8.5 vem dos repositórios oficiais.
  5. Apache + mod_php 8.4 e as extensões mbstring curl xml gd intl zip bcmath gmp soap xsl mysql pgsql sqlite3 opcache; opcionais ldap bz2 tidy redis apcu imagick; ativa rewrite e headers.
  6. php.ini em /etc/php/8.4/{apache2,cli}/conf.d/99-madbuilder.ini: memory_limit 512M, upload de 64M, max_execution_time 300, opcache ligado.
  7. Usuário de deploy e diretório: cria <user>, entra no grupo www-data, cria <path> com 2775 <user>:www-data e ACL padrão. Com --authorized-key, instala a chave em authorized_keys.
  8. VirtualHost em /etc/apache2/sites-available/madbuilder-<slug>.conf: DocumentRoot <path>/public, AllowOverride All; desativa o 000-default.
  9. Banco local (só com --db): PostgreSQL ou MySQL, com o usuário administrador madbuilder_admin. A senha fica em /root/.madbuilder-db-admin.
  10. Cron em /etc/cron.d/madbuilder-<slug>: php artisan schedule:run a cada minuto.
  11. Worker de fila no systemd: madbuilder-<slug>-queue.service. Fica em espera até o primeiro deploy criar o artisan.
  12. Swap de 2 GB quando a máquina tem menos de 2 GB de RAM.
  13. Firewall: se o ufw já estiver ativo, libera OpenSSH e Apache Full. Nunca liga o ufw por conta própria.
  14. HTTPS sempre: com --domain, certbot --apache (Let's Encrypt); sem domínio ou sem DNS público, certificado autoassinado em /etc/ssl/madbuilder/ + VirtualHost :443, e a porta 80 passa a redirecionar para 443. Troque pelo Let's Encrypt depois com certbot --apache -d dominio.
  15. Roda o check no fim e imprime um resumo com os campos exatos para cadastrar o servidor no MadBuilder.

<slug> é o domínio informado ou, sem domínio, o nome da pasta do --path (/var/www/erp → erp).

Rodar de novo é seguro. O script é idempotente: repetir o comando confere o que já existe e só cria o que falta. Para ver o plano sem tocar em nada, acrescente --dry-run.
03

Passo 2 — Cadastrar o servidor no MadBuilder

No MadBuilder, abra Servidores de deploy (barra lateral) e clique em Novo servidor.

  1. Host ou IP do servidor, porta 22, e usuário SSH igual ao --user do passo anterior.
  2. Autenticação: deixe em chave do builder. Se o comando incluiu --authorized-key, a chave já está instalada. Senão, copie a chave pública mostrada na tela e cole em ~/.ssh/authorized_keys do usuário de deploy:
    mkdir -p ~/.ssh && chmod 700 ~/.ssh && nano ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
  3. Caminho: o mesmo --path (/var/www/erp).
  4. Permissões: chmod 775 e Grupo <user>:www-data (por exemplo deploy:www-data).
  5. Salvar e depois Testar conexão. O painel à direita mostra cada verificação.
Por que <user>:www-data, e não só www-data? O MadBuilder faz o deploy conectado como <user>, sem root. Com o diretório em 2775 <user>:www-data, tudo que ele envia já nasce no grupo www-data — o Apache lê e escreve. Se o campo Grupo tiver só www-data, o chown do deploy exige root e o log mostra um aviso a cada publicação. O usuário de deploy não precisa de privilégios: basta escrever no --path.
04

Passo 3 — Verificar requisitos

Na tela Deploy SSH, selecione o servidor e clique em Verificar requisitos. O MadBuilder conecta pela chave, roda o check do instalador no servidor e mostra o resultado passo a passo. O mesmo conjunto aparece em Testar conexão, na tela de servidores.

PassoO que verificaSe falhar
dnsO host resolve para um IP.Confira o nome ou use o IP direto.
tcpA porta SSH responde.Libere a porta 22 no firewall do servidor e do provedor.
authLogin por chave do builder (ou senha).Instale a chave em authorized_keys; confira permissões de ~/.ssh.
osuname -s é Linux e há bash.Windows e macOS param aqui. Use um servidor Linux.
pathO diretório existe e pode ser listado.Rode o provision com o mesmo --path.
writeGrava e apaga um arquivo de teste no diretório.sudo chown -R <user>:www-data <path> && sudo chmod -R 2775 <path>
toolsunzip, tar, gzip; PHP ≥ 8.4.1 64-bit; extensões obrigatórias (pdo mbstring openssl json tokenizer ctype fileinfo curl dom xml gd intl zip bcmath sodium) e ao menos um driver PDO. Extensões de runtime e opcionais viram aviso.Rode o provision de novo. Item isolado: sudo apt install <pacote>.
permsDiretório gravável pelo usuário de deploy, grupo www-data, bit setgid, usuário no grupo, e a pasta de backups <pai>/deploy-backups/<pasta> gravável (o deploy guarda ali o backup e o pacote temporário — falha se nem ela nem o pai aceitarem escrita).Mesmo comando do write; sudo usermod -aG www-data <user>; sudo install -d -m 2775 -o <user> -g www-data <pai>/deploy-backups/<pasta>.
webrootApache ou nginx ativo, VirtualHost apontando para <path>/public, mod_rewrite, módulo PHP na mesma versão da CLI. Só avisos.Rode o provision ou ajuste o VirtualHost à mão.

O resumo no topo da seção diz o estado geral: Servidor pronto, Pronto, com avisos (só itens opcionais faltando), Faltam requisitos (algo obrigatório falhou — o comando de provisionamento aparece embaixo) ou Não é Linux.

05

Passo 4 — Fazer o deploy

Com o servidor pronto, escolha o que vai subir e clique em Fazer deploy:

  • Projeto completo — um pacote .zip com o sistema inteiro, vendor/ incluso, enviado por SFTP e extraído no servidor com unzip -o. É o modo do primeiro deploy.
  • Arquivos — só as páginas e códigos que você marcar, enviados um a um por SFTP. Para atualizações pontuais.

Antes de sobrescrever qualquer coisa, o MadBuilder faz um backup tar.gz da instalação atual em <pai>/deploy-backups/<pasta>/ (por exemplo /var/www/deploy-backups/erp/) e mantém os cinco mais recentes. Se algum pré-requisito faltar, a verificação inicial aborta o deploy antes do backup, com a mensagem e o comando de correção. O log aparece em tempo real no painel à direita.

06

Passo 5 — Concluir no navegador

Depois do primeiro deploy, abra o assistente de instalação do próprio sistema:

https://seu-dominio/install

Sem domínio, use https://IP-do-servidor/install — sempre por https (a porta 80 redireciona; o certificado autoassinado faz o navegador avisar uma vez: Avançado → continuar). O assistente pede um token que prova acesso ao servidor. Ele está em:

sudo cat /var/www/erp/storage/app/install-token.txt
  1. O assistente confere os requisitos (PHP, extensões, permissões).
  2. Pede a conexão com o banco de dados. Marque a opção de criar banco e usuário e informe uma credencial administrativa. Se você usou --db, ela está em /root/.madbuilder-db-admin. Essa credencial é usada uma vez e não fica gravada.
  3. Roda as migrações e a carga inicial.
  4. Cria o usuário administrador com a senha que você escolher e desativa as contas de demonstração. O login do administrador é admin (o e-mail informado é só contato) com essa senha.
  5. Grava o .env e fecha o assistente com storage/mad-installed.lock. A partir daí, /install não abre mais.
Pronto. O sistema está no ar em https://seu-dominio: entre com admin e a senha do assistente. Banco criado, administrador definido, fila e agendador rodando. Os próximos deploys pela tela Deploy SSH só atualizam os arquivos (com backup automático antes).
07

Pós-instalação

Fila de tarefas

E-mails (código 2FA, redefinição de senha, convites) saem por um worker em background. O instalador o deixou como serviço do systemd:

sudo systemctl status madbuilder-<slug>-queue

<slug> é o domínio (ex.: erp-empresa-com-br) ou o nome da pasta do --path; o resumo do provision imprime o nome exato. Até o primeiro deploy a unit fica reiniciando (não existe artisan ainda) — é esperado; depois do /install ela estabiliza sozinha.

Depois de cada deploy, reinicie o worker para carregar o código novo:

cd /var/www/erp && php artisan queue:restart

ou sudo systemctl restart madbuilder-<slug>-queue.

Tarefas agendadas

O cron em /etc/cron.d/madbuilder-<slug> já chama php artisan schedule:run a cada minuto. Nada a fazer — os agendamentos criados no MadBuilder passam a rodar sozinhos.

HTTPS

O provision sempre deixa HTTPS ativo — Let's Encrypt quando o domínio tem DNS público, autoassinado caso contrário. Para trocar o autoassinado pelo Let's Encrypt quando o DNS estiver apontado:

sudo certbot --apache -d seu-dominio

Se o provision ficou no certificado autoassinado (domínio sem DNS público na hora), esse mesmo comando troca para o Let's Encrypt assim que o DNS existir; o VirtualHost autoassinado (madbuilder-<slug>-ssl.conf) pode então ser desativado com a2dissite.

Backups

deploy-backups/ guarda só os arquivos das versões anteriores. O banco de dados não entra. Agende um pg_dump ou mysqldump para fora do servidor.

08

Solução de problemas

SintomaCausaCorreção
403 na raiz do siteO DocumentRoot aponta para a pasta do projeto, não para public/.Confira o VirtualHost ou rode o provision de novo.
500 em toda página logo após o deployPHP abaixo de 8.4.1 ou 32-bit. php -v e php -r 'echo PHP_INT_SIZE;' (precisa ser 8).Rode o provision de novo (ele instala 8.4, ou 8.5 no Ubuntu 26.04).
"'unzip' não está disponível no servidor"Pacote ausente.sudo apt install unzip
"Falha ao criar backup do servidor: mkdir … deploy-backups: Permission denied"O usuário de deploy não escreve em <pai> (ex.: /var/www, do root) e a pasta de backups não existe.sudo install -d -m 2775 -o <user> -g www-data <pai>/deploy-backups/<pasta> — ou rode o provision de novo, que cria a pasta.
Erro de permissão em storage/Diretório sem grupo www-data ou sem escrita para o grupo.sudo chown -R <user>:www-data <path> && sudo chmod -R 2775 <path>/storage <path>/bootstrap/cache
"aviso: chown retornou exit 1" no log do deployCampo Grupo só com www-data — exige root.Use <user>:www-data no cadastro do servidor.
"Autenticação rejeitada pelo servidor"Chave do builder não instalada, ou ~/.ssh com permissões abertas.Cole a chave em authorized_keys; chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys.
Porta 22 não respondeFirewall do servidor (ufw) ou do provedor.Libere a porta para o IP do builder.
"Não é Linux"Servidor Windows ou macOS.Não suportado. Use um servidor Linux.
/install responde 419 Page Expired ao desbloquearPágina aberta em HTTP puro: em produção o cookie de sessão é Secure e o navegador não o devolve — o CSRF falha.Abra por https:// (o provision configura HTTPS e o redirect; num servidor montado à mão, habilite TLS).
/install pede tokenComportamento normal — prova acesso ao servidor.sudo cat <path>/storage/app/install-token.txt
/install diz "já instalado"Existe storage/mad-installed.lock ou já há um administrador no banco.Entre pelo login normal. Para reinstalar de propósito, remova o lock e o banco.
09

Perguntas frequentes

Posso usar nginx em vez de Apache?

O script configura só Apache. Com nginx, faça à mão: root em <path>/public, try_files $uri /index.php?$query_string e PHP-FPM 8.4. O check reconhece nginx ativo e procura o VirtualHost em /etc/nginx/sites-enabled.

Serve PHP 8.2 ou 8.3?

Não. As dependências do sistema exigem PHP 8.4.1 ou superior, 64-bit. Uma versão menor passa em alguns testes e depois dá erro 500 em toda requisição.

Meu banco fica em outro servidor.

Use --db none (o padrão) e informe host, porta e credenciais no assistente /install. O servidor de aplicação só precisa do driver PDO correspondente, que o provision já instala.

Vários projetos no mesmo servidor?

Sim. Rode o provision uma vez por projeto, cada um com seu --path e, de preferência, seu --domain. O slug (nome da pasta ou domínio) separa VirtualHost, cron e worker de fila.

Posso rodar o script de novo?

Sim. Ele é idempotente: confere o que existe e só cria o que falta. Um VirtualHost já com certificado não é sobrescrito.

Preciso deixar a porta 22 aberta para a internet?

Não. Basta liberar o IP do MadBuilder no firewall. Consulte o suporte para o endereço atual.

curl | bash é seguro?

O script é servido por HTTPS a partir do domínio do MadBuilder. Se preferir, baixe o arquivo, leia e execute localmente — o comando alternativo está no Passo 1.

Meu servidor é de intranet, sem domínio público. E o HTTPS?

Rode com --domain erp.empresa.local --ssl self-signed (ou deixe o auto tentar o Let's Encrypt e cair sozinho no autoassinado). O tráfego fica cifrado; o navegador mostra um aviso porque a autoridade não é pública — importe o /etc/ssl/madbuilder/<slug>.crt nas máquinas dos usuários para silenciá-lo.

Preciso instalar Composer ou Node?

Não. O pacote do deploy já traz vendor/ e os assets compilados. O servidor só precisa de PHP e Apache.

10

Referência rápida

Comandos

curl -fsSL https://api.madbuilder.dev/install.sh | sudo bash -s -- provision --path /var/www/erp --user deploy [--php 8.4] [--db pgsql|mysql|none] [--domain erp.exemplo.com.br] [--ssl auto|letsencrypt|self-signed|none] [--email voce@exemplo.com.br] [--authorized-key '...'] [--yes] [--dry-run]
curl -fsSL https://api.madbuilder.dev/install.sh | bash -s -- check --path /var/www/erp [--only tools,perms]

Caminhos

O quêOnde
Raiz pública (DocumentRoot)<path>/public
Token do assistente<path>/storage/app/install-token.txt
Marca de instalação concluída<path>/storage/mad-installed.lock
Backups do deploy (e pacote temporário)<pai>/deploy-backups/<pasta>/
Certificado autoassinado/etc/ssl/madbuilder/<slug>.{crt,key}
VirtualHost/etc/apache2/sites-available/madbuilder-<slug>.conf
Ajustes do PHP/etc/php/8.4/apache2/conf.d/99-madbuilder.ini
Cron do agendador/etc/cron.d/madbuilder-<slug>
Worker de fila/etc/systemd/system/madbuilder-<slug>-queue.service
Credencial admin do banco local/root/.madbuilder-db-admin