OffVPSVPS OFFSHORESuporte

Implantando um aplicativo

Dê à sua primeira API uma release repetível.

Faça uma pequena API funcionar localmente, torne seu processo recuperável e só então conecte seu nome de host e HTTPS. Mantenha o caminho de release e o caminho de volta explícitos.

OffVPS guia de campo · Revisado · 5 min de leitura

Prepare um ambiente pequeno e controlado

Este procedimento tem como alvo um sistema Linux com systemd, uma conta de administrador, um runtime Node.js 24 LTS já instalado, curl e o serviço de sistema empacotado do Caddy. Confirme primeiro as versões instaladas e os caminhos dos pacotes; A página de releases do Node identifica as linhas de release suportadas. Instalação e provisionamento pelo provedor são tarefas separadas. Use uma máquina que você controla e mantenha uma sessão SSH testada e um caminho de recuperação disponíveis. Os nomes first-api e /opt/first-api devem estar sem uso antes de criar este exemplo.

Para HTTPS você também precisa de um domínio que você controla, registros A/AAAA corretos e permissão para expor tráfego web. api.example.com abaixo é um exemplo reservado: substitua-o pelo seu próprio nome de host. Esta API deliberadamente não contém banco de dados, autenticação ou dados de clientes. Ela demonstra um processo repetível, não um produto completo nem uma implantação OffVPS testada.

Verifique o runtime e crie um release

command -v node &&
readlink -f "$(command -v node)" &&
node --version

O restante do exemplo assume que o executável compartilhado verificado é /usr/bin/node. Se o seu for diferente, substitua esse caminho em todas as verificações e em ExecStart. Um runtime dentro do home privado do seu usuário de login não fica automaticamente disponível para um serviço de sistema. Crie a conta de serviço e um diretório de release pertencente ao root, parando se uma conta ou caminho existente inesperado for encontrado.

sudo useradd --system --user-group --home-dir /opt/first-api \
  --shell /usr/sbin/nologin first-api &&
sudo install -d -o root -g root -m 0755 /opt/first-api/releases/001

Usando seu editor com acesso administrativo, salve o seguinte como /opt/first-api/releases/001/server.mjs, pertencente ao root e legível pelo usuário do serviço. O release contém apenas este arquivo; não há dependências de pacote nem segredos.

import http from 'node:http';

const port = Number(process.env.PORT || 3000);
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
  throw new Error('PORT must be an integer from 1024 to 65535');
}
const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  res.setHeader('Cache-Control', 'no-store');
  if (req.method !== 'GET') {
    res.writeHead(405, { Allow: 'GET' });
    res.end(JSON.stringify({ error: 'method_not_allowed' }));
    return;
  }
  if (req.url === '/healthz') {
    res.writeHead(200);
    res.end(JSON.stringify({ status: 'ok', release: '001' }));
  } else if (req.url === '/api/message') {
    res.writeHead(200);
    res.end(JSON.stringify({ message: 'A small app, running clearly.' }));
  } else {
    res.writeHead(404);
    res.end(JSON.stringify({ error: 'not_found' }));
  }
});
server.requestTimeout = 10000;
server.headersTimeout = 10000;
server.keepAliveTimeout = 5000;
server.listen(port, '127.0.0.1');
process.on('SIGTERM', () => {
  server.close(() => process.exit(0));
  setTimeout(() => process.exit(1), 10000).unref();
});

O endereço de loopback explícito mantém o listener da API no próprio servidor. O Caddy será seu ponto de entrada público. O Node HTTP API documenta o tratamento de solicitações, timeouts e desligamento do servidor. Verifique o arquivo como a conta que realmente o executará:

sudo -u first-api /usr/bin/node --check /opt/first-api/releases/001/server.mjs

Dê ao processo uma definição de serviço

Salve /etc/systemd/system/first-api.service com este conteúdo:

[Unit]
Description=First API learning release
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=5

[Service]
Type=simple
User=first-api
Group=first-api
WorkingDirectory=/opt/first-api/releases/001
ExecStart=/usr/bin/node /opt/first-api/releases/001/server.mjs
Environment=NODE_ENV=production
Environment=PORT=3000
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target

A unit usa um usuário dedicado, um executável explícito e um diretório de trabalho versionado. A recuperação automática é limitada por taxa; uma parada intencional do serviço não dispara Restart=on-failure. Veja systemd.service. As restrições de sistema de arquivos se adequam a esta API somente leitura; um aplicativo que grava dados precisa de armazenamento gravável com escopo deliberado. Segredos não pertencem a estas linhas de ambiente. Veja configurações de execução do systemd.

sudo systemd-analyze verify /etc/systemd/system/first-api.service &&
sudo systemctl daemon-reload &&
sudo systemctl start first-api.service &&
sudo systemctl status first-api.service --no-pager &&
curl --fail --show-error http://127.0.0.1:3000/healthz

O && guardas param a sequência colada quando um comando falha. Resolva avisos de validação antes de iniciar e não continue para o próximo bloco após uma verificação falha. Verificação da unit pode detectar problemas de sintaxe e de executável, mas uma verificação bem-sucedida não é prova de um aplicativo funcional. A resposta de health esperada é {"status":"ok","release":"001"}. Se falhar, inspecione sudo journalctl -u first-api.service -n 50 --no-pager antes de reiniciar repetidamente.

Adicione a rota HTTPS após a verificação local

Faça backup da configuração existente do Caddy com um nome de arquivo não utilizado. Adicione este bloco a /etc/caddy/Caddyfile sem substituir sites não relacionados:

api.example.com {
    reverse_proxy 127.0.0.1:3000
}

Para o fluxo padrão de domínio público, o nome de host deve resolver para o servidor, as portas 80/443 devem alcançar o Caddy, e o armazenamento de certificados do Caddy deve permanecer gravável e persistente. Verifique todas as rotas A/AAAA publicadas. Deixe o acesso SSH intacto e mantenha a porta 3000 privada. Estes requisitos vêm de HTTPS automático do Caddy; a sintaxe do upstream está documentada em reverse_proxy.

sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile &&
sudo systemctl reload caddy.service

Recarregue somente após validação bem-sucedida; caddy validate verifica a configuração adaptada. O fluxo de trabalho do serviço empacotado é descrito em Guia de serviço do Caddy. De um cliente separado, solicite https://api.example.com/healthz usando seu nome de host real. Espere uma conexão TLS confiável e a mesma resposta do release, sem contornar as verificações de certificado. Depois verifique /api/message retorna sua mensagem e um caminho desconhecido retorna 404.

Mantenha um release conhecido e um ponto de parada seguro

Depois que ambas as verificações funcionarem, habilite a API para inicializações futuras com sudo systemctl enable first-api.service. Registre a versão do runtime, o arquivo de origem, a unit e a configuração do Caddy. Para o próximo release, crie um novo diretório numerado, verifique sua sintaxe como o usuário do serviço, atualize ambos os caminhos da unit, recarregue o systemd e reinicie a API. Mantenha o diretório anterior até o novo release ser aceito.

Para parar este exemplo, use sudo systemctl stop first-api.service. O Caddy reportará uma falha de upstream enquanto essa rota permanecer configurada; remova apenas esta rota e valide/recarregue o Caddy ao desativá-la. Faça rollback de um release de código com falha selecionando os caminhos da unit anterior e repetindo as verificações. Uma migração posterior de banco de dados precisa de seu próprio plano de recuperação. Continue com o caminho de solicitação do DNS ao aplicativo ou descobrir por que um aplicativo parou.

Documentação utilizada

Referências primárias para esta página. Consulte a documentação da versão instalada em seu próprio ambiente.