Como publicar uma API Hono em uma VPS com Node.js e Docker (domínio e HTTPS incluídos)

API Hono compilada em TypeScript, imagem Node.js 22 e Docker Compose com Caddy na mesma rede: o proxy atende o domínio com HTTPS e encaminha para api:3000.
Tenha acesso root e SSD NVMe, com 10% OFF extra pelo link da Hora de Codar.
Ver a oferta de VPS Parceria Hora de CodarFala aí, beleza? Para publicar uma API Hono em uma VPS, vamos usar o adaptador Node.js, compilar o TypeScript e executar a API atrás do Caddy com HTTPS. Os dois contêineres vão compartilhar uma rede do Docker Compose: o Caddy encaminha as requisições para api:3000, sem publicar a porta da API na internet.
O exemplo parte de uma VPS dedicada a este projeto, com Docker Engine e o plugin Docker Compose instalados, acesso administrativo e um domínio sob seu controle. Se já existem aplicações nas portas 80 e 443, adapte a configuração ao proxy existente antes de executar os comandos.
O que você precisa para hospedar a API Hono
- Node.js 22 para desenvolver e compilar o projeto deste exemplo.
- Docker Engine e Docker Compose na VPS.
- Acesso por SSH e permissão para operar o Docker.
- Um domínio com registro DNS apontando para o servidor.
- Portas 80 e 443 disponíveis para o Caddy, além da porta usada pelo seu SSH.
O adaptador @hono/node-server permite servir aplicações Hono no Node.js. O release v2 do adaptador informa que o suporte ao Node.js 18 foi removido. Aqui padronizamos o exemplo em Node.js 22, inclusive na imagem Docker.
Para este cenário, a recomendação principal da Hora de Codar é a VPS da Hostinger. Este artigo contém links de afiliado: a Hora de Codar pode receber uma comissão pela contratação. O acesso administrativo da VPS permite configurar o ambiente para a aplicação; confirme no plano escolhido os recursos e condições que atendem ao seu projeto.
Passo 1: criar a aplicação Hono para Node.js
Crie o projeto e selecione o template nodejs quando o assistente perguntar, conforme a documentação do Hono:
npm create hono@latest my-app
cd my-app
npm install
Em src/index.ts, deixe uma rota simples e uma porta explícita para este exemplo:
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Node.js!'))
serve({
fetch: app.fetch,
port: 3000,
})
Rode o servidor de desenvolvimento:
npm run dev
Abra http://localhost:3000. A resposta esperada da rota é Hello Node.js!. Encerre o servidor local antes de seguir para o build, se ele ainda estiver ocupando o terminal.
O erro comum aqui é mudar a porta da aplicação e esquecer de atualizar o proxy. Neste tutorial, a porta interna da API é sempre 3000.
Passo 2: definir a saída do TypeScript
O contêiner vai executar dist/index.js. Portanto, o build precisa preservar essa relação entre o arquivo de entrada e o diretório de saída.
Instale as ferramentas de compilação, caso ainda não estejam nas dependências do template:
npm install --save-dev typescript @types/node
Para esta aplicação simples, configure tsconfig.json assim:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}
No package.json, mantenha as dependências do projeto e confira estes campos. O trecho abaixo é um recorte para mesclar ao arquivo, não um substituto do package.json inteiro:
Mais controle no próximo deploy.
Configure sua aplicação em uma VPS Hostinger com acesso root. Escolha os recursos conforme o que seu projeto precisa.
- SSD NVMe
- AMD EPYC
- Backups semanais
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
}
}
O TypeScript usa outDir para escolher a pasta de saída; rootDir influencia a estrutura preservada nessa pasta, como explica a documentação do compilador.
Confira o resultado:
npm run build
npm start
A rota deve continuar respondendo em http://localhost:3000. Se o arquivo gerado estiver em outro caminho, alinhe a configuração antes de criar a imagem. Não adianta configurar um CMD para um arquivo que o build não produz.
Passo 3: montar a imagem Docker da API
Este Dockerfile adapta o exemplo multi-stage do Hono ao layout src/index.ts usado aqui. As cópias separam o código-fonte dos arquivos de configuração para preservar a pasta src durante a compilação.
Crie Dockerfile na raiz:
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build && npm prune --omit=dev
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder --chown=node:node /app/package.json ./package.json
COPY --from=builder --chown=node:node /app/node_modules ./node_modules
COPY --from=builder --chown=node:node /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]
Mantenha o package-lock.json no projeto: o npm ci depende dele e exige que esteja compatível com o package.json.
Crie também .dockerignore:
node_modules
dist
.git
.env
O EXPOSE 3000 documenta a porta usada pela aplicação. A publicação de portas é uma configuração separada do Docker. Neste exemplo, a API não terá um mapeamento de porta no host; o acesso externo passa pelo Caddy.
O erro comum deste passo é copiar o conteúdo de src para o lugar errado e depois tentar compilar com rootDir apontando para uma pasta inexistente. Confira os caminhos do Dockerfile junto com os do tsconfig.json.
Passo 4: ligar API e Caddy pela mesma rede
Na raiz do projeto, crie compose.yaml:
services:
api:
build: .
restart: unless-stopped
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
Crie o Caddyfile no mesmo diretório, trocando o domínio pelo seu:
api.seu-dominio.com.br {
reverse_proxy api:3000
}
A rede padrão do Docker Compose permite que os serviços se encontrem pelo nome. Por isso o backend é api:3000: api é o nome do serviço no Compose, e 3000 é a porta do processo Hono dentro do contêiner.

Crie sistemas com IA para vender
Prompts, modelos e checklists para criar e publicar seu sistema com IA e preparar a oferta para o primeiro cliente.
Quero o e-book gratuito Receba o livro e os bônus no seu e-mail.Não use localhost:3000 nesse Caddyfile. Dentro do contêiner do Caddy, localhost aponta para o próprio contêiner do Caddy, e não para o serviço da API.
Os volumes preservam os dados do Caddy quando o contêiner é recriado. A imagem oficial do Caddy documenta os diretórios de configuração e dados; /data inclui o estado utilizado para os certificados.
Passo 5: preparar a VPS e o domínio
Acesse a VPS pelo usuário e pela porta configurados para o seu servidor:
ssh SEU_USUARIO@IP_DA_VPS
Se escolheu um template com Docker na Hostinger, confira o que já está instalado antes de instalar novamente:
docker --version
docker compose version
No painel que administra o DNS do domínio, crie um registro A para api.seu-dominio.com.br apontando para o IPv4 da VPS. Se houver registro AAAA, ele também precisa apontar corretamente para um IPv6 que o servidor atenda.
No firewall do provedor e no firewall do sistema operacional, permita o tráfego necessário ao SSH e às portas 80 e 443. Não crie uma regra pública para a porta 3000 neste exemplo.
A documentação de HTTPS automático do Caddy detalha os requisitos de domínio, conectividade e armazenamento. Se o DNS ainda aponta para outro servidor ou as portas necessárias estão bloqueadas, resolva isso antes de esperar um certificado válido.
Transfira para um diretório de trabalho da VPS o código-fonte, package.json, package-lock.json, tsconfig.json, Dockerfile, .dockerignore, compose.yaml e Caddyfile. Não copie credenciais locais para a imagem.
Não reinstale o sistema operacional de uma VPS que já contém dados para seguir este tutorial. Use uma instância adequada ao projeto ou prepare uma migração com backup.
Passo 6: subir os serviços e conferir o resultado
No diretório do projeto na VPS, valide a configuração e execute o build:
docker compose config
docker compose up -d --build
docker compose ps
docker compose logs --tail=100 api caddy
O resultado esperado é a API em execução e o Caddy encaminhando as requisições do domínio configurado. Depois que o DNS e a emissão do certificado estiverem corretos, confira:
curl https://api.seu-dominio.com.br/
curl -I http://api.seu-dominio.com.br/
A primeira chamada deve retornar Hello Node.js!. A segunda permite conferir o redirecionamento HTTP para HTTPS.
Esses comandos são etapas de validação para o seu ambiente. O sucesso do build, sozinho, não comprova que DNS, firewall e certificado estejam corretos.
A API não responde: o que conferir primeiro
Se o Caddy responde com erro de gateway, olhe os logs dos dois serviços. Confira se a API iniciou, se o arquivo dist/index.js existe na imagem e se o Caddyfile aponta para api:3000.
Se o certificado não foi emitido, confira os registros A e AAAA, as portas 80 e 443 e o domínio escrito no Caddyfile. Um endereço IPv6 incorreto também precisa ser corrigido.
Se os dados do Caddy desaparecem ao recriar os contêineres, confira os volumes. Para atualizar a aplicação mantendo esses volumes, use novamente docker compose up -d --build. Evite docker compose down -v como rotina: a opção -v remove volumes nomeados do projeto.
Para planejar manutenção, vale consultar também as boas práticas de Docker na VPS. Inclua backup dos dados relevantes, uma forma de voltar à imagem anterior e uma conferência da rota pública depois de cada alteração.
Mais conteúdo de VPS no canal
O canal Hora de Codar tem conteúdo complementar sobre aplicações e infraestrutura. O vídeo de apoio abaixo é uma referência adicional; os arquivos e comandos deste guia estão descritos nos passos anteriores.
Se ainda precisa escolher o servidor, confira a VPS indicada para este projeto e dimensione os recursos para a sua aplicação. O objetivo é sair com uma API acessível pelo domínio, com proxy configurado e um procedimento de atualização que você consiga manter.
Até o próximo post!
Quer aprender mais sobre inteligência artificial e programação na prática? Conheça o canal Hora de Codar no YouTube e acompanhe os próximos vídeos.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 48min
Blog | Mais populares

Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação A popularidade da automação de processos com o n8n está em alta, principalmente […]

Checklist de segurança n8n VPS 2026: proteja sua automação
Confira o checklist de segurança n8n VPS 2026 e mantenha sua automação protegida. Veja práticas essenciais e atualizadas para seu servidor. Manter seu ambiente de […]
Quanto custa uma VPS? Preço atualizado 2026
Quando se fala em quanto custa uma VPS, é preciso contextualizar o tema a partir de um provedor específico, porque o preço só faz sentido […]
