Why Self-Host Instead of Vercel?
Vercel excels at serverless deployment but can become expensive at scale, especially with function invocations, bandwidth overages, and team seats. Self-hosting gives you predictable costs, no vendor lock-in, and full control over your infrastructure.
Migration Options
- Static export: For static/SSG sites, export HTML and serve with Nginx
- Node.js server: For SSR/ISR Next.js apps, run the Node.js server directly
- Docker: Containerize for portability and easy deployment
- Coolify/CapRover: Self-hosted PaaS for Vercel-like experience
Static Site Export
# In next.config.js:
module.exports = {
output: "export",
}
# Build static export
npm run build
# The out/ directory contains your static site
# Serve with Nginx:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri.html $uri/ /404.html;
}
}
SSR Next.js with Node.js
# Build the application
npm run build
# Start in production
NODE_ENV=production npm start
# Or: node .next/standalone/server.js
# Use PM2 for process management
npm install -g pm2
pm2 start npm --name "my-app" -- start
pm2 save
pm2 startup
Docker Deployment
# Dockerfile for Next.js
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
# docker-compose.yml
version: "3.8"
services:
app:
build: .
ports: ["3000:3000"]
environment:
- NODE_ENV=production
restart: always
Nginx Reverse Proxy
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
location /_next/static/ {
alias /var/www/app/.next/static/;
expires 365d;
access_log off;
}
}
Replacing Vercel Features
- Edge Functions: Use Nginx + Lua or Cloudflare Workers
- Analytics: Plausible or Umami (self-hosted)
- Preview Deployments: Coolify supports PR previews
- Serverless Functions: Convert to API routes in your Node.js server
- Image Optimization: Use next/image with sharp (works self-hosted)
CI/CD Setup
# GitHub Actions for automated deployment
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ssh user@server "cd /app && git pull && npm ci && npm run build && pm2 restart my-app"