Pular para o conteúdo

VPS e variáveis

Um projeto blog roda num processo só: o painel fica em /painel e o site publicado em /. Os dados ficam em storage/ (banco SQLite, backups, mídias e a cópia de trabalho dos builds), fora do git.

Esta página segue o passo a passo do README.md que o slash create gera no projeto. Crie o projeto antes com slash create <pasta> --template blog (veja Modelos do blog). O slash create também deixa na pasta deploy/ os três arquivos de exemplo usados aqui. Eles não ficam ativos na sua máquina: você os copia para a VPS e preenche.

  • Um servidor Linux com systemd.
  • Bun 1.4.3, a versão que o README do projeto fixa no instalador.
  • Caddy, para o HTTPS.
  • GNU tar. O painel chama o tar do sistema com opções do GNU (--quoting-style), e outro tar, como o do BSD, não serve.
  • unzip e curl. O instalador do Bun usa os dois.
  • Um disco com espaço para o banco, os backups e a cópia de trabalho dos builds. A pasta storage/ precisa estar no mesmo disco do projeto (veja Vários projetos, mídia e atualização).

Cada projeto roda com um usuário de sistema próprio, slash-<projeto>. <projeto> é o nome da pasta do projeto, sem acento, em minúsculas e com hífens no lugar dos outros caracteres. Nos comandos e nos exemplos desta página, projeto aparece literal; no seu projeto, a pasta deploy/ já traz o nome trocado. Se o nome passar de 26 caracteres, o usuário sai cortado e com um hash no fim, como explica Vários projetos, mídia e atualização.

Crie o usuário e instale o Bun para ele:

sudo useradd --system --create-home slash-<projeto>

sudo -u slash-<projeto> -H sh -c 'curl -fsSL https://bun.sh/install | bash -s "bun-v1.4.3"'

O PATH do sudo e o do systemd não trazem o Bun. Por isso, todo comando desta página chama /home/slash-<projeto>/.bun/bin/bun pelo caminho completo.

Copie a pasta do projeto para /srv/<projeto>, sem node_modules, dist e storage. Dê a pasta ao usuário do serviço e instale as dependências como ele:

sudo chown -R slash-<projeto>:slash-<projeto> /srv/<projeto>

sudo -u slash-<projeto> -H sh -c 'cd /srv/<projeto> && /home/slash-<projeto>/.bun/bin/bun install'

O banco, a cópia de trabalho dos builds e o dist/ são criados nessa pasta, pelo próprio usuário do serviço.

Crie /etc/slash-<projeto>.env com dono root e permissão 600. O arquivo de exemplo é este:

deploy/slash-projeto.env.example

# Copie para /etc/slash-<projeto>.env (dono root, permissão 600) e preencha.
# Um valor com espaço vai entre aspas, como o MAIL_FROM.
PORT=4330
PUBLIC_URL=https://seu-dominio.com.br
PANEL_SECRET=troque-por-openssl-rand-hex-32
TRUST_PROXY=1
RESEND_API_KEY=re_troque
MAIL_FROM="Painel <painel@seu-dominio.com.br>"

Um valor com espaço vai entre aspas, como o MAIL_FROM. Estas são as variáveis que o painel lê, com a regra de cada uma:

VariávelObrigatóriaPadrãoValidaçãoMensagem
PORT Sim — use um inteiro de 1 a 65535. PORT: defina a porta do painel (um número de 1 a 65535).
PUBLIC_URL Sim — defina o endereço público, como https://painel.exemplo.com (sem caminho nem credenciais; http só para localhost). PUBLIC_URL: defina o endereço público, como https://painel.exemplo.com (sem caminho nem credenciais; http só para localhost).
PANEL_SECRET Sim — use pelo menos 32 caracteres (gere com: openssl rand -hex 32). PANEL_SECRET: use pelo menos 32 caracteres (gere com: openssl rand -hex 32).
TRUST_PROXY Sim — use 1 (atrás do Caddy, o proxy da VPS) ou 0 (sem proxy na frente). TRUST_PROXY: use 1 (atrás do Caddy, o proxy da VPS) ou 0 (sem proxy na frente).
HOST Não 127.0.0.1 use um endereço IP ou nome de máquina (padrão 127.0.0.1). HOST: use um endereço IP ou nome de máquina (padrão 127.0.0.1).
DATABASE_URL Não sqlite://<projeto>/storage/db.sqlite — —
RESEND_API_KEY Sim — — RESEND_API_KEY: defina a chave do Resend (em produção o e-mail nunca vai ao console).
MAIL_FROM Sim — defina o remetente, como Painel <painel@exemplo.com>. MAIL_FROM: defina o remetente, como Painel <painel@exemplo.com>.

Avisos de produção

  • TRUST_PROXY=1 com HOST=0.0.0.0: o servidor aceita conexões de fora do proxy, e quem as faz escolhe o próprio X-Forwarded-For (os limites por endereço deixam de valer). Com o Caddy na mesma máquina, deixe o HOST em 127.0.0.1; senão use TRUST_PROXY=0 ou feche a porta para o resto da rede.
  • TRUST_PROXY=0: o servidor escuta só em 127.0.0.1, então todo acesso chega de 127.0.0.1. Se houver um proxy (Caddy) na frente, use TRUST_PROXY=1; sem proxy, ignore este aviso.

Algumas observações:

  • PANEL_SECRET deve ficar fixo. Trocá-lo invalida os formulários abertos, quebra os links de descadastro dos e-mails já enviados da newsletter e muda os hashes de IP dos bloqueios.
  • PUBLIC_URL é a origem dos links dos e-mails, como a confirmação de inscrição e a redefinição de senha.
  • DATABASE_URL é opcional. Sem ela, o banco fica em storage/db.sqlite.
  • Atrás do Caddy, use TRUST_PROXY=1. Sem proxy na frente, use 0.
  • Em produção, o processo não sobe sem RESEND_API_KEY, MAIL_FROM válido, PANEL_SECRET com 32 caracteres ou mais e as demais variáveis obrigatórias. A mensagem de erro lista tudo que falta de uma vez, em Configuração de produção inválida. Corrija:.
  • HOST vem com 127.0.0.1 por padrão. O servidor escuta só na própria máquina, e é o Caddy que recebe a conexão de fora.

A descrição completa de cada variável está na página de referência das variáveis, em Variáveis de ambiente.

O arquivo de exemplo do serviço é este:

deploy/slash-projeto.service.example

# Copie para /etc/systemd/system/slash-projeto.service na VPS. Crie o usuário do serviço e dê a pasta a ele:
#   useradd --system --create-home slash-projeto
#   chown -R slash-projeto:slash-projeto /srv/projeto
# Copie o arquivo de ambiente (deploy/slash-projeto.env.example) para /etc/slash-projeto.env e depois:
#   systemctl daemon-reload && systemctl enable --now slash-projeto
[Unit]
Description=slash-projeto (painel e site)
After=network-online.target
Wants=network-online.target

[Service]
User=slash-projeto
WorkingDirectory=/srv/projeto
# O systemd não lê o perfil do usuário: sem o PATH abaixo, `bun run start` e o build do publicador (que chama `bun`) não acham o bun.
Environment=PATH=/home/slash-projeto/.bun/bin:/usr/local/bin:/usr/bin:/bin
Environment=NODE_ENV=production
EnvironmentFile=/etc/slash-projeto.env
# Ajuste o caminho do bun instalado para o usuário do serviço.
ExecStart=/home/slash-projeto/.bun/bin/bun run start
Restart=on-failure
# O build roda em subprocesso de até 5 minutos; 1 GB cobre o painel e o build.
MemoryMax=1G
NoNewPrivileges=true
# O serviço lê o sistema em modo somente leitura; /srv/projeto segue gravável para o banco, os builds e o site.
ProtectSystem=full
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Copie-o para /etc/systemd/system/slash-<projeto>.service. Confira o caminho do bun em ExecStart= e em PATH=, e depois rode:

sudo systemctl daemon-reload && sudo systemctl enable --now slash-<projeto>

O serviço roda bun run start, que no projeto blog executa bun src/server.ts com NODE_ENV=production. O limite de memória é de 1 GB por serviço, que cobre o painel e o build do site.

O arquivo de exemplo do Caddy é este:

deploy/Caddyfile.example

# Copie para /etc/caddy/Caddyfile na VPS e troque o domínio.
# Um bloco por site: outro projeto na mesma VPS entra como outro bloco, com outra porta.
# O Caddy obtém e renova o HTTPS sozinho; a porta é a PORT do arquivo de ambiente do serviço.
seu-dominio.com.br {
	reverse_proxy 127.0.0.1:4330
}

Copie-o para /etc/caddy/Caddyfile, troque o domínio e recarregue o Caddy:

sudo systemctl reload caddy

O Caddy obtém e renova o certificado sozinho. A porta em reverse_proxy tem de ser a mesma PORT do arquivo de ambiente.

Com o serviço no ar, crie o primeiro administrador e faça a primeira publicação em Primeiro admin e publicação.