Self-hosting Next.js with Docker
Standalone output, a multi-stage Dockerfile and Nginx in front. The same setup this site runs on.
Running Next.js on your own VPS, without being tied to a platform, is easier than you might think. This site runs on the setup below.
Turn on standalone output
One line in next.config.ts makes the build put only the files needed to run into a separate folder:
const nextConfig = { output: "standalone" };That keeps the full node_modules folder out of the image, so the image gets much smaller.
A multi-stage Dockerfile
Install dependencies, build, then copy only the output into a small image:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production HOSTNAME=0.0.0.0 PORT=3000
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
USER node
CMD ["node", "server.js"]Put Nginx in front
The container only listens on 127.0.0.1:3000. Nginx talks to the outside world:
server {
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}For the certificate, sudo certbot --nginx -d example.com is enough. Certbot sets up renewal too.
Updating
Shipping a new version takes two commands:
docker compose build
docker compose up -dYou can wire this into a GitHub Actions workflow so it runs on every push to main.
Have a project in mind?
An idea, an unfinished job or a server that needs moving. Whatever it is, write to me and I'll reply the same day.
Get in touch
