Featured

Complete Docker Setup Guide for Next.js on VPS

T
Team
·12 min read
#docker#nextjs#vps#deployment#devops#containers

Complete Docker Setup Guide for Next.js on VPS


Deploying Next.js applications on a VPS can be challenging, but Docker makes it much easier by providing consistent environments and simplified deployment. This guide will walk you through setting up a production-ready Next.js application with Docker on a VPS.


Prerequisites


Before we begin, make sure you have:


  • A VPS with Ubuntu 20.04 or later
  • SSH access to your VPS
  • A Next.js application ready to deploy
  • Basic knowledge of Linux commands

  • Step 1: Install Docker on Your VPS


    First, connect to your VPS via SSH and install Docker:


    bash(22 lines, showing 15)
    # Update package index
    sudo apt update
    
    # Install prerequisites
    sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
    
    # Add Docker's official GPG key
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    
    # Add Docker repository
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    # Install Docker
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

    Step 2: Create Dockerfile for Next.js


    In your Next.js project root, create a Dockerfile:


    dockerfile(47 lines, showing 15)
    # Use the official Node.js runtime as base image
    FROM node:18-alpine AS base
    
    # Install dependencies only when needed
    FROM base AS deps
    RUN apk add --no-cache libc6-compat
    WORKDIR /app
    
    # Copy package files
    COPY package.json package-lock.json* ./
    RUN npm ci
    
    # Rebuild the source code only when needed
    FROM base AS builder
    WORKDIR /app

    Step 3: Configure Next.js for Standalone Output


    Update your next.config.js to enable standalone output:


    javascript
    /** @type {import('next').NextConfig} */
    const nextConfig = {
      output: 'standalone',
      // Other config options...
    }
    
    module.exports = nextConfig

    Step 4: Create docker-compose.yml


    Create a docker-compose.yml file for easier management:


    yaml(22 lines, showing 15)
    version: '3.8'
    
    services:
      nextjs:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: nextjs-app
        restart: unless-stopped
        ports:
          - "3000:3000"
        environment:
          - NODE_ENV=production
          - NEXT_PUBLIC_API_URL=https://api.projectdomain.com
        volumes:

    Step 5: Create .dockerignore


    Create a .dockerignore file to exclude unnecessary files:


    dockerignore
    node_modules
    .next
    .git
    .gitignore
    README.md
    .env*.local
    npm-debug.log*
    yarn-debug.log*
    yarn-error.log*
    .DS_Store
    *.pem

    Step 6: Build and Run Docker Container


    On your VPS, clone your repository and build the Docker image:


    bash
    # Clone your repository
    git clone https://github.com/yourusername/your-nextjs-app.git
    cd your-nextjs-app
    
    # Build the Docker image
    docker compose build
    
    # Run the container
    docker compose up -d
    
    # Check if container is running
    docker ps
    
    # View logs
    docker compose logs -f

    Step 7: Set Up Nginx Reverse Proxy (Optional)


    For production, set up Nginx as a reverse proxy:


    bash
    # Install Nginx
    sudo apt install -y nginx
    
    # Create Nginx configuration
    sudo nano /etc/nginx/sites-available/nextjs

    Add this configuration:


    nginx(16 lines, showing 15)
    server {
        listen 80;
        server_name projectdomain.com www.projectdomain.com;
    
        location / {
            proxy_pass http://localhost:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            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;
        }

    Enable the site and restart Nginx:


    bash
    sudo ln -s /etc/nginx/sites-available/nextjs /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl restart nginx

    Step 8: Set Up SSL with Let's Encrypt


    Secure your application with SSL:


    bash
    # Install Certbot
    sudo apt install -y certbot python3-certbot-nginx
    
    # Obtain SSL certificate
    sudo certbot --nginx -d projectdomain.com -d www.projectdomain.com
    
    # Auto-renewal is set up automatically

    Best Practices


    1. Use Multi-stage Builds

    Multi-stage builds reduce the final image size significantly.


    2. Set Environment Variables Securely

    Use Docker secrets or environment files for sensitive data:


    yaml
    services:
      nextjs:
        env_file:
          - .env.production

    3. Health Checks

    Add health checks to your docker-compose.yml:


    yaml
    services:
      nextjs:
        healthcheck:
          test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/api/health"]
          interval: 30s
          timeout: 10s
          retries: 3
          start_period: 40s

    4. Resource Limits

    Set resource limits to prevent resource exhaustion:


    yaml
    services:
      nextjs:
        deploy:
          resources:
            limits:
              cpus: '1'
              memory: 1G
            reservations:
              cpus: '0.5'
              memory: 512M

    5. Log Management

    Configure log rotation:


    yaml
    services:
      nextjs:
        logging:
          driver: "json-file"
          options:
            max-size: "10m"
            max-file: "3"

    Troubleshooting


    Container won't start

    Check logs: docker compose logs nextjs


    Port already in use

    Change the port mapping in docker-compose.yml or stop the conflicting service.


    Build fails

    Ensure all dependencies are in package.json and check Node.js version compatibility.


    Conclusion


    You now have a production-ready Next.js application running on your VPS with Docker. This setup provides:


  • Consistency - Same environment across development and production
  • Isolation - Application runs in its own container
  • Scalability - Easy to scale horizontally
  • Maintainability - Simple updates and rollbacks

  • Remember to keep your Docker images updated and monitor your application's performance regularly.


    Share this article

    Enjoyed this article?

    Support our work and help us create more free content for developers.

    Stay Updated

    Get the latest articles and updates delivered to your inbox.