Containers
    Build Tool

    Deploy Apps with Nixpacks on a VPS

    Turn your source code into production-ready containers without writing a single Dockerfile. Supports Node.js, Python, Go, Rust, Ruby, PHP, Java, and 20+ more languages.

    At a Glance

    ProjectNixpacks by Railway
    LicenseMIT
    Recommended PlanRamNode Cloud VPS 2GB or higher
    OSUbuntu 22.04 / 24.04 LTS
    LanguagesNode.js, Python, Go, Rust, Ruby, PHP, Java, .NET, and 20+ more
    StatusMaintenance mode (Railpack is successor); fully functional and widely used
    Estimated Setup Time15–20 minutes

    Prerequisites

    • A RamNode VPS with at least 1 GB RAM (2 GB recommended for larger builds)
    • Ubuntu 22.04 or 24.04 LTS
    • Root or sudo access to the server
    • A domain name (optional but recommended for HTTPS)
    • Basic familiarity with the Linux command line
    1

    Initial Server Setup

    Update system
    sudo apt update && sudo apt upgrade -y
    Install build tools
    sudo apt install -y curl git wget ca-certificates gnupg lsb-release
    2

    Install Docker

    Nixpacks uses Docker BuildKit to produce container images. Docker must be installed first.

    Add Docker repository and install
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    Enable and verify
    sudo systemctl enable docker
    sudo systemctl start docker
    docker --version
    Run Docker without sudo (optional)
    sudo usermod -aG docker $USER
    newgrp docker
    3

    Install Nixpacks

    Install via official script
    curl -sSL https://nixpacks.com/install.sh | bash
    Verify installation
    nixpacks --version

    Alternatively, install a specific version from GitHub releases:

    Install specific version
    curl -LO https://github.com/railwayapp/nixpacks/releases/download/v1.40.0/nixpacks-v1.40.0-amd64.deb
    sudo dpkg -i nixpacks-v1.40.0-amd64.deb
    4

    Build Your First Application

    Create a Sample Node.js App

    Create project directory
    mkdir ~/sample-app && cd ~/sample-app
    package.json
    {
      "name": "nixpacks-demo",
      "version": "1.0.0",
      "scripts": {
        "start": "node index.js"
      },
      "dependencies": {
        "express": "^4.18.0"
      }
    }
    index.js
    const express = require('express');
    const app = express();
    const PORT = process.env.PORT || 3000;
    
    app.get('/', (req, res) => {
      res.json({
        message: 'Hello from Nixpacks on RamNode!',
        timestamp: new Date().toISOString()
      });
    });
    
    app.listen(PORT, '0.0.0.0', () => {
      console.log(`Server running on port ${PORT}`);
    });

    Generate a Build Plan

    Inspect the plan
    nixpacks plan .

    This outputs a JSON object showing the detected language, packages, install command, and start command.

    Build and Run

    Build the image
    nixpacks build . --name sample-app
    Run the container
    docker run -d --name sample-app -p 3000:3000 -e PORT=3000 sample-app
    Test
    curl http://localhost:3000
    5

    Understand the Build Process

    Plan phase: Nixpacks analyzes the source directory, detects the language from marker files (package.json, requirements.txt, go.mod, Cargo.toml), and generates a build plan.

    Build phase: Nixpacks converts the plan into a Dockerfile, then uses Docker BuildKit to produce the final OCI-compliant container image.

    Supported languages: Node.js, Python, Go, Rust, Ruby, PHP, Java, .NET/C#, Elixir, Deno, Dart, Haskell, Crystal, Clojure, Scala, Swift, Zig, and static HTML sites.

    6

    Customize Builds with nixpacks.toml

    nixpacks.toml — basic
    [phases.setup]
    nixPkgs = ['nodejs', 'yarn']
    aptPkgs = ['libpq-dev']
    
    [phases.install]
    cmds = ['yarn install --frozen-lockfile']
    
    [phases.build]
    cmds = ['yarn run build']
    
    [start]
    cmd = 'yarn run start'

    Adding System Dependencies

    nixpacks.toml — extra packages
    [phases.setup]
    nixPkgs = ['...', 'ffmpeg']       # '...' preserves auto-detected packages
    aptPkgs = ['libmagickwand-dev']

    Specifying Language Versions

    nixpacks.toml — versions
    [variables]
    NIXPACKS_NODE_VERSION = '20'
    NIXPACKS_PYTHON_VERSION = '3.12'

    Or at the command line:

    Version via CLI
    nixpacks build . --name my-app --env NIXPACKS_NODE_VERSION=20

    Custom Build Phases

    nixpacks.toml — custom phase
    [phases.migrate]
    cmds = ['npx prisma migrate deploy']
    dependsOn = ['build']
    
    [start]
    cmd = 'node dist/server.js'
    7

    Python Application Example

    Create Python app
    mkdir ~/python-app && cd ~/python-app
    requirements.txt
    flask==3.0.0
    gunicorn==21.2.0
    app.py
    from flask import Flask, jsonify
    import os
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello():
        return jsonify({
            'message': 'Python app built with Nixpacks on RamNode',
            'python': 'auto-detected'
        })
    
    if __name__ == '__main__':
        port = int(os.environ.get('PORT', 5000))
        app.run(host='0.0.0.0', port=port)
    Procfile
    web: gunicorn app:app --bind 0.0.0.0:$PORT
    Build and run
    nixpacks build . --name python-app
    docker run -d --name python-app -p 5000:5000 -e PORT=5000 python-app
    8

    Go Application Example

    Create Go app
    mkdir ~/go-app && cd ~/go-app
    go mod init go-app
    main.go
    package main
    
    import (
        "fmt"
        "net/http"
        "os"
    )
    
    func main() {
        port := os.Getenv("PORT")
        if port == "" {
            port = "8080"
        }
    
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, `{"message": "Go app on RamNode via Nixpacks"}`)
        })
    
        fmt.Printf("Listening on port %s\n", port)
        http.ListenAndServe("0.0.0.0:"+port, nil)
    }
    Build and run
    nixpacks build . --name go-app
    docker run -d --name go-app -p 8080:8080 -e PORT=8080 go-app
    9

    Nginx Reverse Proxy with SSL

    Install Nginx and Certbot
    sudo apt install -y nginx certbot python3-certbot-nginx
    /etc/nginx/sites-available/myapp
    server {
        listen 80;
        server_name yourdomain.com;
    
        location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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_cache_bypass $http_upgrade;
        }
    }
    Enable and reload
    sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx
    Obtain SSL certificate
    sudo certbot --nginx -d yourdomain.com
    10

    Container Management and Updates

    Rebuild After Code Changes

    Rebuild and replace
    cd ~/sample-app
    git pull
    
    nixpacks build . --name sample-app
    
    docker stop sample-app
    docker rm sample-app
    docker run -d --name sample-app -p 3000:3000 -e PORT=3000 sample-app

    Clean Up Old Images

    Prune images
    docker image prune -f
    docker image prune -a -f

    Logs and Auto-Restart

    View logs
    docker logs sample-app
    docker logs -f sample-app
    Auto-restart on boot
    docker run -d --name sample-app --restart unless-stopped -p 3000:3000 -e PORT=3000 sample-app
    11

    Environment Variables and Secrets

    Build-Time Variables

    Pass env vars at build
    nixpacks build . --name my-app \
      --env NODE_ENV=production \
      --env DATABASE_URL=postgresql://user:pass@db:5432/mydb

    Runtime Variables

    Pass env vars at runtime
    docker run -d --name my-app \
      -p 3000:3000 \
      -e PORT=3000 \
      -e DATABASE_URL=postgresql://user:pass@db:5432/mydb \
      -e REDIS_URL=redis://redis:6379 \
      -e SECRET_KEY=your-secret-key-here \
      my-app
    Use an env file
    docker run -d --name my-app \
      -p 3000:3000 \
      --env-file .env.production \
      my-app
    12

    Docker Compose for Multi-Container Deployments

    docker-compose.yml
    version: '3.8'
    
    services:
      app:
        image: sample-app
        container_name: sample-app
        restart: unless-stopped
        ports:
          - "3000:3000"
        environment:
          - PORT=3000
          - DATABASE_URL=postgresql://appuser:apppass@db:5432/appdb
          - REDIS_URL=redis://redis:6379
        depends_on:
          - db
          - redis
    
      db:
        image: postgres:16-alpine
        container_name: app-db
        restart: unless-stopped
        environment:
          - POSTGRES_USER=appuser
          - POSTGRES_PASSWORD=apppass
          - POSTGRES_DB=appdb
        volumes:
          - pgdata:/var/lib/postgresql/data
    
      redis:
        image: redis:7-alpine
        container_name: app-redis
        restart: unless-stopped
    
    volumes:
      pgdata:
    Build and start
    nixpacks build . --name sample-app
    docker compose up -d
    13

    Build Optimization Tips

    Enable BuildKit Caching

    Set BuildKit
    export DOCKER_BUILDKIT=1

    Pin Nixpkgs for Reproducible Builds

    Pin nixpkgs
    nixpacks build . --name my-app --pin

    Reduce Image Size

    Separate dependencies from devDependencies in package.json. Keep requirements.txt lean. Use a custom start command:

    nixpacks.toml — slim start
    [start]
    cmd = 'node dist/index.js'

    Troubleshooting

    • "No provider found" — Ensure the correct marker file exists (package.json, requirements.txt, go.mod, etc.).
    • Out of memory during builds — Upgrade to a 2 GB plan or add swap space.
    • Docker permission denied — Add your user to the docker group and re-login.
    • Port conflicts — Check with sudo lsof -i :3000.
    • Slow builds — First-time builds are slow; subsequent builds use layer caching.