Exemplo mínimo de uso com Bun (baseado na documentação oficial)
Aviso: Este exemplo é puramente acadêmico, baseado na documentação oficial do Next.js. Para um ambiente de produção real, ajustes adicionais de segurança, performance e monitoramento são necessários.
1 - Ajustar o next.config.ts para "Standalone":
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
};
export default nextConfig;
2 - Criar um .dockerignore:
############################################################
# Production-ready .dockerignore for a Next.js (Vercel-style) app
# Keeps Docker builds fast, lean, and free of development files.
############################################################
# Dependencies (installed inside Docker, never copied)
node_modules/
.pnpm-store/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Next.js build outputs (always generated during `next build`)
.next/
out/
dist/
build/
.vercel/
# Tests and testing output (not needed in production images)
coverage/
.nyc_output/
__tests__/
__mocks__/
jest/
cypress/
cypress/screenshots/
cypress/videos/
playwright-report/
test-results/
.vitest/
vitest.config.*
jest.config.*
cypress.config.*
playwright.config.*
*.test.*
*.spec.*
# Local development and editor files
.git/
.gitignore
.gitattributes
.vscode/
.idea/
*.swp
*.swo
*~
*.log
# Environment variables (only commit template files)
.env
.env*.local
.env.development
.env.test
.env.production.local
# Docker configuration files (not needed inside build context)
Dockerfile*
.dockerignore
compose.yaml
compose.yml
docker-compose*.yaml
docker-compose*.yml
# Documentation
*.md
docs/
# CI/CD configuration files
.github/
.gitlab-ci.yml
.travis.yml
.circleci/
Jenkinsfile
# Cache directories and temporary data
.cache/
.parcel-cache/
.eslintcache
.stylelintcache
.swc/
.turbo/
.tmp/
.temp/
# TypeScript build metadata
*.tsbuildinfo
# Sensitive or unnecessary configuration files
*.pem
.editorconfig
.prettierrc*
prettier.config.*
.eslintrc*
eslint.config.*
.stylelintrc*
stylelint.config.*
.babelrc*
*.iml
*.ipr
*.iws
# OS-specific junk
.DS_Store
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.ini
3 - Criar o Dockerfile:
# ============================================
# Stage 1: Dependencies Installation Stage
# ============================================
# This Dockerfile.bun is specifically configured for projects using Bun
# For npm/pnpm or yarn, refer to the Dockerfile instead
FROM oven/bun:1 AS dependencies
# Set working directory
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json bun.lock* ./
# Install project dependencies with frozen lockfile for reproducible builds
RUN --mount=type=cache,target=/root/.bun/install/cache \
bun install --no-save --frozen-lockfile
# ============================================
# Stage 2: Build Next.js application in standalone mode
# ============================================
FROM oven/bun:1 AS builder
# Set working directory
WORKDIR /app
# Copy project dependencies from dependencies stage
COPY --from=dependencies /app/node_modules ./node_modules
# Copy application source code
COPY . .
ENV NODE_ENV=production
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1
# Build Next.js application
RUN bun run build
# ============================================
# Stage 3: Run Next.js application
# ============================================
FROM oven/bun:1 AS runner
# Set working directory
WORKDIR /app
# Set production environment variables
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the run time.
# ENV NEXT_TELEMETRY_DISABLED=1
# Copy production assets
COPY --from=builder --chown=bun:bun /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown bun:bun .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=bun:bun /app/.next/standalone ./
COPY --from=builder --chown=bun:bun /app/.next/static ./.next/static
# If you want to persist the fetch cache generated during the build so that
# cached responses are available immediately on startup, uncomment this line:
# COPY --from=builder --chown=bun:bun /app/.next/cache ./.next/cache
# Switch to non-root user for security best practices
USER bun
# Expose port 3000 to allow HTTP traffic
EXPOSE 3000
# Start Next.js standalone server with Bun
CMD ["bun", "server.js"]
4 - Criar o Docker compose:
# Bun service (use with: docker compose up nextjs-standalone-with-bun --build)
services:
app:
build:
context: .
dockerfile: Dockerfile
image: nextjs-standalone-bun-image
container_name: nextjs-app
environment:
NODE_ENV: production
PORT: "3000"
HOSTNAME: "0.0.0.0"
expose:
- "3000"
restart: unless-stopped
networks:
- app-network
nginx:
image: nginx:stable-alpine
container_name: nginx-proxy
depends_on:
- app
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/nginx.conf:ro
- certbot_www:/var/www/certbot
- certbot_conf:/etc/letsencrypt
restart: unless-stopped
networks:
- app-network
certbot:
image: certbot/certbot:latest
container_name: certbot
volumes:
- certbot_www:/var/www/certbot
- certbot_conf:/etc/letsencrypt
entrypoint: >
sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot --quiet; sleep 12h; done'
restart: unless-stopped
volumes:
certbot_www:
certbot_conf:
networks:
app-network:
driver: bridge
5 - Criar um template básico do nginx:
server {
listen 80;
server_name seudominio.com www.seudominio.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
proxy_pass http://app:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
6 - Buildar a imagem Docker e Subir o container:
Automatizado:
make build && make up
Manual:
docker compose build
docker compose up -d
7 - Opcional - Criar um Makefile mínimo para automatizar o processo:
# Makefile - App Nextjs + Docker + VPS Example
PROJECT_NAME=App Nextjs
DOCKER_IMAGE_NAME=app-next-js
DOCKER_CONTAINER_NAME=app-next-js
COMPOSE_FILE=docker-compose.yaml
build:
docker compose -f $(COMPOSE_FILE) build
up:
docker compose -f $(COMPOSE_FILE) up -d
stop:
docker compose -f $(COMPOSE_FILE) stop
clean: stop
docker compose -f $(COMPOSE_FILE) down --remove-orphans
docker rmi -f $(DOCKER_IMAGE_NAME) >/dev/null 2>&1 || true
rm -rf node_modules .next >/dev/null 2>&1 || true
Conclusão
Com essa arquitetura mínima, você tem uma aplicação Next.js rodando em modo standalone dentro de um container Docker, servida pelo Nginx como proxy reverso e com certificado SSL automatizado via Certbot — tudo orquestrado pelo Docker Compose em uma VPS.
O Makefile opcional simplifica o dia a dia com comandos curtos para build, subir e limpar o ambiente. É uma base funcional e direta, sem complexidade desnecessária.
Lembre-se: este exemplo é um ponto de partida acadêmico. Para produção real, considere variáveis de ambiente seguras, healthchecks, logging, CI/CD e hardening do servidor.
Top comments (0)