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.
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ãoSecure; em HTTP puro a sessão não volta e o/installresponde 419. O script redireciona a porta 80 para 443.
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).
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ção | check | provision | Padrão · o que faz |
|---|---|---|---|
| --path <dir> | obrigatório | obrigatório | Raiz do sistema. O Apache aponta para <path>/public. |
| --user <nome> | opcional | obrigatório | Usuário SSH de deploy. Criado com useradd -m se não existir. |
| --group <nome> | opcional | opcional | www-data. Grupo do servidor web, dono do diretório junto com o usuário. |
| --php 8.4|8.5 | — | opcional | Sem 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 | — | opcional | none. Instala um banco local e cria o usuário administrador madbuilder_admin. |
| --domain <fqdn> | — | opcional | Define o ServerName do VirtualHost e liga o HTTPS (veja --ssl). |
| --ssl auto|letsencrypt| self-signed|none | — | opcional | auto: 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> | — | opcional | E-mail de contato do certbot (avisos de renovação). |
| --authorized-key '<chave>' | — | opcional | Chave pública instalada em ~<user>/.ssh/authorized_keys. A tela já inclui a chave do builder. |
| --no-cron · --no-queue --no-swap · --no-certbot | — | opcional | Pula a etapa correspondente (--no-certbot = --ssl none). |
| --yes | — | opcional | Não pede confirmação. Útil em automação. |
| --dry-run | — | opcional | Mostra o que faria, sem alterar nada. |
| --machine | opcional | — | Saída em linhas legíveis por máquina (é o que o MadBuilder lê). |
| --only os,tools,perms,webroot | opcional | — | 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
- 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. - Mostra o plano e pede confirmação.
--yespula essa pergunta. - Pacotes base via apt:
ca-certificates curl gnupg unzip tar gzip cron acl. - Repositório do PHP:
ppa:ondrej/phpno Ubuntu 22.04/24.04,packages.sury.orgno Debian 12; no Ubuntu 26.04 nenhum — o PHP 8.5 vem dos repositórios oficiais. - Apache + mod_php 8.4 e as extensões
mbstring curl xml gd intl zip bcmath gmp soap xsl mysql pgsql sqlite3 opcache; opcionaisldap bz2 tidy redis apcu imagick; ativarewriteeheaders. - 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. - Usuário de deploy e diretório: cria
<user>, entra no grupowww-data, cria<path>com2775 <user>:www-datae ACL padrão. Com--authorized-key, instala a chave emauthorized_keys. - VirtualHost em
/etc/apache2/sites-available/madbuilder-<slug>.conf:DocumentRoot <path>/public,AllowOverride All; desativa o000-default. - Banco local (só com
--db): PostgreSQL ou MySQL, com o usuário administradormadbuilder_admin. A senha fica em/root/.madbuilder-db-admin. - Cron em
/etc/cron.d/madbuilder-<slug>:php artisan schedule:runa cada minuto. - Worker de fila no systemd:
madbuilder-<slug>-queue.service. Fica em espera até o primeiro deploy criar oartisan. - Swap de 2 GB quando a máquina tem menos de 2 GB de RAM.
- Firewall: se o
ufwjá estiver ativo, liberaOpenSSHeApache Full. Nunca liga o ufw por conta própria. - 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 comcertbot --apache -d dominio. - Roda o
checkno 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).
--dry-run.
Passo 2 — Cadastrar o servidor no MadBuilder
No MadBuilder, abra Servidores de deploy (barra lateral) e clique em Novo servidor.
- Host ou IP do servidor, porta
22, e usuário SSH igual ao--userdo passo anterior. - 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_keysdo usuário de deploy:mkdir -p ~/.ssh && chmod 700 ~/.ssh && nano ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
- Caminho: o mesmo
--path(/var/www/erp). - Permissões: chmod
775e Grupo<user>:www-data(por exemplodeploy:www-data). - Salvar e depois Testar conexão. O painel à direita mostra cada verificação.
<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.
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.
| Passo | O que verifica | Se falhar |
|---|---|---|
| dns | O host resolve para um IP. | Confira o nome ou use o IP direto. |
| tcp | A porta SSH responde. | Libere a porta 22 no firewall do servidor e do provedor. |
| auth | Login por chave do builder (ou senha). | Instale a chave em authorized_keys; confira permissões de ~/.ssh. |
| os | uname -s é Linux e há bash. | Windows e macOS param aqui. Use um servidor Linux. |
| path | O diretório existe e pode ser listado. | Rode o provision com o mesmo --path. |
| write | Grava e apaga um arquivo de teste no diretório. | sudo chown -R <user>:www-data <path> && sudo chmod -R 2775 <path> |
| tools | unzip, 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>. |
| perms | Diretó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>. |
| webroot | Apache 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.
Passo 4 — Fazer o deploy
Com o servidor pronto, escolha o que vai subir e clique em Fazer deploy:
- Projeto completo — um pacote
.zipcom o sistema inteiro,vendor/incluso, enviado por SFTP e extraído no servidor comunzip -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.
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
- O assistente confere os requisitos (PHP, extensões, permissões).
- 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. - Roda as migrações e a carga inicial.
- 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. - Grava o
.enve fecha o assistente comstorage/mad-installed.lock. A partir daí,/installnão abre mais.
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).
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.
Solução de problemas
| Sintoma | Causa | Correção |
|---|---|---|
| 403 na raiz do site | O 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 deploy | PHP 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 deploy | Campo 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 responde | Firewall 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 desbloquear | Pá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 token | Comportamento 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. |
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.
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 |