NodeLink
Advenced

Docker

Ship your audio server in a container. Same code, anywhere. 🐳

Docker: Because Production Should Just Work

Look, we've all been there. You spend hours getting NodeLink running perfectly on your laptop. Everything works. Audio is crisp. No crashes. Life is good.

Then you deploy to production and... it doesn't work. Wrong Node version. Missing dependencies. Something about native modules. Your weekend is gone.

Docker fixes this. It's not magic. It's just consistency. Same environment, same dependencies, same behavior—whether you're running on your gaming PC, a $5 VPS, or an enterprise Kubernetes cluster.

What Docker Actually Does

Docker wraps your application with everything it needs (Node.js, system libraries, native modules) into an image. That image runs the same way everywhere. No surprises. No "works on my machine" excuses.


Why Bother With Containers?

Because you have better things to do than fight with package managers at 3 AM trying to get sodium-native to compile.

Docker gives you instant setup where you don't need to manually install Node.js v22+. No hunting down build tools for native modules. No dependency resolution nightmares. Just pull the image and run. Your NodeLink instance lives in perfect isolation, in its own world where it can't interfere with your system and nothing can interfere with it. Clean slate every time you start it.

Updates become trivial. New version? Just docker compose pull && docker compose up -d and you're done. Need to rollback? Same commands, different tag. The portability is real too—it runs on Linux, Windows, macOS, ARM, x86, cloud, bare metal. If Docker exists there, NodeLink runs there.

Zero Native Build Issues

Native modules like sodium-native for encryption are already compiled in the image. No gcc, no python, no build-essential needed.

Worker Architecture Ready

The image is optimized for NodeLink's worker-based architecture. Cluster mode works out of the box without manual configuration.

Production Hardened

Health checks, restart policies, and security best practices are configured. Not something you cobbled together from a tutorial.

True Portability

The same image that runs on your laptop runs in production. No environment-specific bugs. No surprise differences.


The Setup Is Already Done

The NodeLink repository includes a production-ready Docker setup. No assembly required.

We already built a multi-stage Dockerfile that compiles native modules in a build stage and copies only what's needed to the runtime stage. The result is a lean image optimized for size and security. The docker-compose.yml includes every single configuration option NodeLink supports, all documented inline with examples. Health checks verify NodeLink is actually responding, not just that the container is running. Restart policies ensure it comes back up automatically if it crashes. Volume mounts are configured for local music files and log persistence.

You don't need to piece this together yourself. You don't need to understand Docker internals. Just clone the repo, adjust the handful of settings that matter to you, and launch.


Getting Started

Install Docker

You need Docker and Docker Compose. If you don't have them yet, get them from the official sources.

For Ubuntu/Debian, use the official Docker repository for the latest version:

# 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=$(dpkg --print-architecture) 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 Engine
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

For other distributions, check the official installation guide.

Download and install Docker Desktop for Windows from docker.com.

Docker Desktop includes both Docker Engine and Docker Compose. After installation, you'll need to restart your computer.

Make sure WSL2 is enabled if you're on Windows 10/11. Docker Desktop will prompt you to install it if needed.

Download and install Docker Desktop for Mac from docker.com.

Docker Desktop includes both Docker Engine and Docker Compose. Works on both Intel and Apple Silicon Macs.

Verify everything is working:

docker --version
docker compose version

If both commands output version numbers, you're ready.

Get the repository to your machine:

git clone https://github.com/PerformanC/NodeLink.git
cd NodeLink

You now have everything. The Dockerfile, the docker-compose.yml, all of it.

Configure Your Instance

Open docker-compose.yml in your editor. You'll see a massive file with every configuration option documented. Most of it you can leave as-is. Here's what you must change:

environment:
  NODELINK_SERVER_PASSWORD: "youshallnotpass" # ⚠️ CHANGE THIS NOW

Don't Skip This

Using the default password in production is like leaving your front door open with a sign that says "free stuff inside." Change it. Use something long and random.

Optional but recommended configurations depend on what you need:

If you want Spotify support, you'll need credentials from the Spotify Developer Dashboard:

NODELINK_SOURCES_SPOTIFY_ENABLED: "true"
NODELINK_SOURCES_SPOTIFY_CLIENTID: "your_actual_spotify_client_id"
NODELINK_SOURCES_SPOTIFY_CLIENTSECRET: "your_actual_spotify_client_secret"

If you want better YouTube support (helps with age-restricted and some region-locked content), get a token from cipher.kikkia.dev:

NODELINK_SOURCES_YOUTUBE_CIPHER_TOKEN: "your_cipher_token"

If you want to use all your CPU cores for better performance under load, enable cluster mode:

NODELINK_CLUSTER_ENABLED: "true"
NODELINK_CLUSTER_WORKERS: "0" # 0 means use all available CPU cores

Everything else has sensible defaults. You can explore the 200+ other options in the file when you need them.

Launch It

One command:

docker compose up -d

Docker will build the NodeLink image from the Dockerfile, compile native modules, install dependencies, and start the server. The -d flag runs it in detached mode (background).

This takes a few minutes the first time while it builds the image. Subsequent starts are instant.

Verify It's Alive

Check if NodeLink is responding:

curl http://localhost:2333/version

You should see version information. If you do, NodeLink is running and ready to connect to your Discord bot.

If something went wrong, check the logs:

docker compose logs -f nodelink

The -f flag follows the logs in real-time. Press Ctrl+C to exit.


Understanding the Configuration

The docker-compose.yml file is massive because it exposes every single configuration option NodeLink supports as environment variables. Most of them you'll never touch. Here's what's actually in there:


Common Operations

Commands you'll use regularly:

# Start NodeLink in background
docker compose up -d

# Stop NodeLink
docker compose down

# Restart NodeLink (reload config changes)
docker compose restart

# Check if running
docker compose ps
# View logs (follow mode)
docker compose logs -f nodelink

# View last 100 lines
docker compose logs --tail=100 nodelink

# View logs from specific time
docker compose logs --since 30m nodelink
# Update to latest version
cd NodeLink
git pull
docker compose up -d --build

# Or using Docker Hub images
docker compose pull
docker compose up -d
# Access container shell
docker compose exec nodelink sh

# Run commands inside container
docker compose exec nodelink npm run --version

Using Pre-built Images

Don't want to build from source every time? Use the pre-built images from Docker Hub:

services:
  nodelink:
    image: performanc/nodelink:latest
    # ... rest of your config ...

Available tags:

latest

Most recent stable release. Updated with each new version. Safe for production.

v3.1.1

Specific version tags. Pin to a version for consistency. Useful when you want predictable behavior.

dev

Bleeding edge from main branch. Gets new features first. May break occasionally. Not for production.

Using pre-built images means faster deployments. No compile time. Just pull and run. The tradeoff is slightly larger images since they're built for multiple architectures.


Local Music Files

Want to play music from your server's hard drive? NodeLink's local source lets you stream files directly from the filesystem.

Create Music Directory

Make a folder for your music files:

mkdir local-music

Put your audio files there. NodeLink supports common formats like MP3, FLAC, WAV, OGG, M4A, and more.

Mount Volume

Edit your docker-compose.yml to mount the directory:

services:
  nodelink:
    volumes:
      - ./local-music:/app/music
    environment:
      NODELINK_SOURCES_LOCAL_ENABLED: "true"
      NODELINK_SOURCES_LOCAL_BASEPATH: "/app/music/"

The volume mount makes your local-music folder appear inside the container at /app/music. The basepath tells NodeLink where to look for files.

Load Tracks

Restart NodeLink to apply changes:

docker compose restart

Now you can load tracks using the file:// protocol:

file:///app/music/song.mp3
file:///app/music/albums/album1/track.flac

The path must start with the basepath you configured. NodeLink resolves the file and streams it like any other source.

Security Note

Local file access is powerful but requires careful configuration. NodeLink validates paths to prevent directory traversal attacks. Still, only enable this if you control the filesystem and know who can access the API.


Production Deployment

Running NodeLink in production requires a few extra considerations beyond just starting the container.

Reverse Proxy Setup

NodeLink should sit behind a reverse proxy in production for SSL termination and security. Here's an Nginx example:

server {
    listen 80;
    server_name audio.yourdomain.com;
    
    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name audio.yourdomain.com;
    
    # SSL certificates (use certbot for Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/audio.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/audio.yourdomain.com/privkey.pem;
    
    location / {
        proxy_pass http://localhost:2333;
        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;
        
        # WebSocket support
        proxy_read_timeout 86400;
    }
}

This configuration handles HTTPS, WebSocket upgrades, and proper header forwarding. Get SSL certificates from Let's Encrypt using certbot. It's free and automated.

Resource Limits

Prevent NodeLink from consuming all system resources if something goes wrong:

services:
  nodelink:
    deploy:
      resources:
        limits:
          cpus: '2.0'      # Max 2 CPU cores
          memory: 2G       # Max 2GB RAM
        reservations:
          cpus: '0.5'      # Reserve half a core
          memory: 512M     # Reserve 512MB RAM

These limits depend on your player count. More simultaneous players need more resources. Monitor actual usage and adjust accordingly.

Health Checks

Docker can monitor if NodeLink is actually responding, not just that the container is running:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:2333/version"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s

If the health check fails three times, Docker marks the container as unhealthy. Combined with restart policies, this provides automatic recovery from crashes or hangs.

Firewall Configuration

If NodeLink runs on a remote server, allow incoming connections:

# UFW (Ubuntu/Debian)
sudo ufw allow 2333/tcp

# firewalld (CentOS/RHEL)
sudo firewall-cmd --add-port=2333/tcp --permanent
sudo firewall-cmd --reload

Only open ports you actually use. If NodeLink is behind a reverse proxy, you might only need to open 80/443 for the proxy and keep 2333 local-only.

Security Checklist

Before going live, verify these points:


Troubleshooting

Container Won't Start

Check the logs for specific errors:

docker compose logs nodelink

Common problems and fixes:

Port already in use: Something else is listening on 2333. Either stop that process or change NodeLink's port in docker-compose.yml:

ports:
  - "2334:2333"  # Use 2334 externally, 2333 internally

Permission denied: Docker doesn't have permission to bind the port or access volumes. On Linux, add your user to the docker group:

sudo usermod -aG docker $USER

Log out and back in for the change to take effect.

Invalid configuration: Check for typos in docker-compose.yml. YAML is whitespace-sensitive. Use a validator if unsure.

Can't Connect from Discord Bot

First, verify NodeLink is accessible from outside the container:

curl http://your-server-ip:2333/version

If this fails, check your firewall rules. If it succeeds but your bot still can't connect, verify the password matches between your bot config and docker-compose.yml.

For remote servers, ensure the firewall allows incoming connections:

sudo ufw status

The port (default 2333) should be listed as allowed.

High CPU Usage

Check how many players are active:

curl http://localhost:2333/v4/stats -H "Authorization: yourPassword"

Look at the players and playingPlayers counts. High CPU with many players is normal. If CPU is high with few players, enable cluster mode:

NODELINK_CLUSTER_ENABLED: "true"
NODELINK_CLUSTER_WORKERS: "0"  # Use all cores

Restart after changing the config.

Audio Cutting Out

This usually indicates network issues or event loop blocking. Check frame statistics in the stats endpoint:

curl http://localhost:2333/v4/stats -H "Authorization: yourPassword"

Look at frameStats. If deficit is positive or nulled is increasing, audio is being dropped. Try increasing the update interval:

NODELINK_PLAYERUPDATEINTERVAL: "1000"

Also check network latency between your server and Discord voice servers. High latency causes problems.

Memory Growing Over Time

External memory grows with active players. This is normal. Each player holds audio buffers for smooth playback. Memory should stabilize once player count is constant. If memory keeps growing even without new players, that might indicate a leak. Report it with logs and reproduction steps.


The Real Talk

Docker makes deploying NodeLink almost trivial. You don't need to be a DevOps expert. You don't need to understand multi-stage builds or image layers or any of that.

The repository already has everything configured. A production-ready Dockerfile optimized for NodeLink's native modules and worker architecture. A comprehensive docker-compose.yml with every option documented. Health checks and restart policies. Security features enabled by default.

Just clone it, change the password, and run docker compose up -d. That's literally the deployment process.

Everything else in this document is optional. The defaults work. The configuration makes sense. The security is reasonable. You can deploy NodeLink to production with a handful of environment variables and be confident it'll run reliably.

You can go from zero to streaming audio in about 5 minutes.


What's Next?

Now that NodeLink is containerized and running:

The code is open. The configs are documented. The community is active. Go build something cool with it. 💙

On this page