Self-Hosting
The Minecraft Heads API can be self-hosted on your own server. This guide covers local development, production configuration, Docker deployment, and Railway deployment.
Prerequisites
- Node.js 18+ -- The API uses modern JavaScript features and native dependencies.
- Build tools -- The
canvasandsharpnpm packages require native compilation. On most systems, these install prebuilt binaries automatically. If they fail, you may need to install system dependencies.
System Dependencies for Canvas
On Debian/Ubuntu:
sudo apt-get install -y build-essential libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev
On Fedora:
sudo dnf install gcc-c++ cairo-devel pango-devel libjpeg-turbo-devel giflib-devel librsvg2-devel
On macOS (via Homebrew):
brew install pkg-config cairo pango libpng jpeg giflib librsvg
Quick Start
Clone the repository and install dependencies:
git clone https://github.com/thejacedev/McHeads-API.git
cd McHeads-API
npm install
Start the development server with hot reload:
npm run dev
The API will start on port 3005 by default. Test it with:
curl -o test_head.png http://localhost:3005/head/Notch/128
For production without hot reload:
npm start
Environment Variables
Create a .env file in the project root. You can copy the included example:
cp .env.example .env
Available Variables
| Variable | Default | Description |
|---|---|---|
PORT |
3005 |
The port the HTTP server listens on |
DATABASE_URL |
(none) | PostgreSQL connection string. If not set, the API uses a local SQLite file |
DATABASE_SSL |
true |
Set to false to disable SSL for the PostgreSQL connection |
Minimal Configuration (SQLite)
For local development or small deployments, no configuration is needed. The API creates a SQLite database file (new_minecraft_heads.db) in the project root automatically:
PORT=3005
This is the simplest setup. SQLite handles caching, stats, and health logs in a single file with no external dependencies.
PostgreSQL Configuration
For production deployments with higher traffic, configure PostgreSQL by setting DATABASE_URL:
PORT=3005
DATABASE_URL=postgresql://mcheads:password@localhost:5432/mcheads
The API creates the required tables automatically on startup (mcheads_stats, mcheads_cache, mcheads_health_logs). Table names are prefixed with mcheads_ when using PostgreSQL, so the API can share a database with other applications without naming conflicts.
If your PostgreSQL instance does not use SSL (common for local development), disable it:
DATABASE_URL=postgresql://mcheads:password@localhost:5432/mcheads
DATABASE_SSL=false
Database Details
SQLite (Default)
- Database file:
new_minecraft_heads.dbin the project root - Uses WAL (Write-Ahead Logging) journal mode for better concurrent read performance
- Tables:
stats,cache,health_logs - No setup required; the file is created on first run
- The database file is excluded from version control via
.gitignore
PostgreSQL
- Requires an existing PostgreSQL server (version 12+)
- Tables:
mcheads_stats,mcheads_cache,mcheads_health_logs - SSL enabled by default (set
DATABASE_SSL=falseto disable) - Connection pooling handled by the
pglibrary'sPoolclass - Tables are created automatically on startup via
CREATE TABLE IF NOT EXISTS
Both backends provide identical functionality. The API abstracts the differences internally.
Docker Deployment
Create a Dockerfile in the project root:
FROM node:20-slim
# Install canvas system dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libcairo2-dev \
libjpeg-dev \
libpango1.0-dev \
libgif-dev \
librsvg2-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3005
CMD ["node", "server.js"]
Build and run:
docker build -t mcheads-api .
docker run -d \
-p 3005:3005 \
--name mcheads \
mcheads-api
Docker with PostgreSQL
Use Docker Compose to run the API alongside a PostgreSQL instance:
# docker-compose.yml
version: "3.8"
services:
api:
build: .
ports:
- "3005:3005"
environment:
- PORT=3005
- DATABASE_URL=postgresql://mcheads:mcheads@db:5432/mcheads
- DATABASE_SSL=false
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=mcheads
- POSTGRES_PASSWORD=mcheads
- POSTGRES_DB=mcheads
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
pgdata:
Start the stack:
docker compose up -d
The API will be available at http://localhost:3005. PostgreSQL data is persisted in the pgdata Docker volume.
Railway Deployment
Railway can deploy the API directly from a GitHub repository.
Push your code to a GitHub repository (or fork the original).
Create a new project on Railway and connect your GitHub repo.
Railway detects the Node.js project automatically and runs
npm installfollowed bynpm start.Add a PostgreSQL plugin to the project from the Railway dashboard.
Set the environment variables in the Railway service settings:
PORT=3005 DATABASE_URL=${{Postgres.DATABASE_URL}}Railway injects the
DATABASE_URLfrom the PostgreSQL plugin automatically when you reference it with${{Postgres.DATABASE_URL}}.Deploy. Railway assigns a public URL to your service.
The API works on Railway's free and paid tiers. The canvas native dependency compiles successfully in Railway's build environment without additional configuration.
Reverse Proxy with Nginx
For production, place the API behind Nginx to handle TLS termination and static caching:
server {
listen 443 ssl http2;
server_name api.mcheads.org;
ssl_certificate /etc/letsencrypt/live/api.mcheads.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.mcheads.org/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3005;
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;
# Cache rendered images at the proxy level
proxy_cache_valid 200 1h;
}
}
Process Management
For production deployments on a VPS, use a process manager to keep the API running:
systemd
Create /etc/systemd/system/mcheads.service:
[Unit]
Description=Minecraft Heads API
After=network.target
[Service]
Type=simple
User=mcheads
WorkingDirectory=/opt/mcheads-api
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=10
Environment=PORT=3005
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl enable mcheads
sudo systemctl start mcheads
PM2
npm install -g pm2
pm2 start server.js --name mcheads
pm2 save
pm2 startup
Verifying the Installation
After starting the API, verify that everything is working:
# Health check (returns JSON)
curl http://localhost:3005/health
# Render a head (saves a PNG file)
curl -o test.png http://localhost:3005/head/Notch/128
# Check stats
curl http://localhost:3005/allstats
The health endpoint checks connectivity to the Mojang API and reports the overall system status. A green status means all systems are operational.
Graceful Shutdown
The API listens for SIGINT (Ctrl+C) and closes the database connection before exiting. This prevents SQLite WAL file corruption and ensures PostgreSQL connections are released cleanly.