I D H A M .
Published

Deploy a Next.js App to VPS Using Docker

Authors

3 min read

Deploying a Next.js app to a VPS might sound intimidating, especially if you're new to Docker or server-side deployment. This tutorial walks you through deploying a Next.js app to a VPS using Docker in a clean and scalable way.

What We'll Build

  • Ubuntu-based VPS (e.g., DigitalOcean, Linode)
  • Docker and Docker Compose for deployment
  • Optional: Traefik as a reverse proxy. You can read previous article about Set up Traefik
  • Your own domain (e.g., myportfolio.com)
  • Free HTTPS with Let's Encrypt
  • No database (for static/SPA apps)

Requirements

Make sure you have:

  • A running VPS with SSH access
  • A domain you control
  • Next.js app ready to deploy
  • Docker and Docker Compose installed on your VPS

If not yet, install Docker:

sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sh
sudo apt install docker-compose-plugin
docker -v
docker compose version

Directory Structure

/var/www/
└── my-nextjs-app/
├── docker-compose.yml
├── .env
└── app/

1. Prepare Your Next.js Code

Create or copy your Next.js project:

npx create-next-app@latest app

Upload to VPS:

scp -r app/ root@your-vps-ip:/var/www/my-nextjs-app/app

2. Create Dockerfile

In /var/www/my-nextjs-app/app:

FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
COPY . .
RUN npm run build
FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD ["npm", "start"]

3. Create docker-compose.yml

version: '3.8'
services:
nextjs:
container_name: my-nextjs-app
build:
context: ./app
dockerfile: Dockerfile
restart: always
ports:
- '3000:3000'
environment:
- NODE_ENV=production
networks:
- default

4. Run the App

cd /var/www/my-nextjs-app
docker compose up -d --build

Access via: http://your-vps-ip:3000


5. Point Your Domain

In your domain DNS:

A @ your-vps-ip

6. (Optional) Add Traefik Reverse Proxy + SSL

a. Folder structure

/var/www/traefik/
├── traefik.yml
├── docker-compose.yml
└── acme.json

b. traefik.yml

api:
dashboard: true
entryPoints:
web:
address: ':80'
websecure:
address: ':443'
certificatesResolvers:
letsencrypt:
acme:
email: you@example.com
storage: acme.json
httpChallenge:
entryPoint: web

c. docker-compose.yml

version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
command:
- --configFile=/etc/traefik/traefik.yml
ports:
- '80:80'
- '443:443'
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml
- ./acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock
networks:
- proxy
networks:
proxy:
external: true

d. Start Traefik

touch acme.json
chmod 600 acme.json
docker compose up -d

e. Add labels to your Next.js app:

labels:
- 'traefik.enable=true'
- 'traefik.http.routers.my-nextjs-app.rule=Host(`mydomain.com`)'
- 'traefik.http.routers.my-nextjs-app.entrypoints=websecure'
- 'traefik.http.routers.my-nextjs-app.tls.certresolver=letsencrypt'

7. Restart and Access

docker compose up -d --build

Visit: https://mydomain.com


With this setup, you have a solid and scalable foundation to deploy your Next.js apps in production — ready to grow with your future projects.