Skip to main content

Manual Deployment

This guide covers deploying PlexMCP without Docker, useful for custom infrastructure or existing server setups.

Prerequisites

System Requirements

  • Linux server (Ubuntu 22.04 LTS recommended)
  • PostgreSQL 15+ (16 recommended)
  • Redis 7+
  • Rust 1.75+ (for building from source)
  • Node.js 20+ (for frontend)

Build Tools

# Ubuntu/Debian
sudo apt update
sudo apt install -y build-essential pkg-config libssl-dev

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Install Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

Database Setup

Install PostgreSQL

# Install PostgreSQL 16
sudo apt install -y postgresql-16 postgresql-contrib-16

# Start PostgreSQL
sudo systemctl enable postgresql
sudo systemctl start postgresql

Create Database

# Switch to postgres user
sudo -u postgres psql

# Create user and database
CREATE USER plexmcp WITH PASSWORD 'your_secure_password';
CREATE DATABASE plexmcp OWNER plexmcp;

# Enable required extensions
\c plexmcp
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

\q

Configure PostgreSQL

Edit /etc/postgresql/16/main/pg_hba.conf to allow local connections:

# IPv4 local connections:
host plexmcp plexmcp 127.0.0.1/32 scram-sha-256

Restart PostgreSQL:

sudo systemctl restart postgresql

Redis Setup

Install Redis

# Install Redis
sudo apt install -y redis-server

# Enable and start
sudo systemctl enable redis-server
sudo systemctl start redis-server

Configure Redis (Optional)

For production, edit /etc/redis/redis.conf:

# Enable persistence
appendonly yes
appendfsync everysec

# Set memory limit
maxmemory 512mb
maxmemory-policy allkeys-lru

# Bind to localhost only
bind 127.0.0.1

Build PlexMCP

Clone Repository

git clone https://github.com/PlexMCP/PlexMCP-OSS.git
cd plexmcp

Build Backend (API)

# Build release binary
cargo build --release

# Binary location
ls -la target/release/plexmcp-api

Build Frontend

cd web

# Install dependencies
npm install

# Build for production
npm run build

cd ..

Configuration

Generate Secrets

# Generate all secrets
JWT_SECRET=$(openssl rand -hex 32)
API_KEY_HMAC_SECRET=$(openssl rand -hex 32)
TOTP_ENCRYPTION_KEY=$(openssl rand -hex 32)

echo "JWT_SECRET=$JWT_SECRET"
echo "API_KEY_HMAC_SECRET=$API_KEY_HMAC_SECRET"
echo "TOTP_ENCRYPTION_KEY=$TOTP_ENCRYPTION_KEY"

Create Environment File

cat > .env << EOF
# Database
DATABASE_URL=postgresql://plexmcp:your_secure_password@localhost:5432/plexmcp

# Redis
REDIS_URL=redis://localhost:6379

# Server
BIND_ADDRESS=0.0.0.0:8080
PUBLIC_URL=https://api.yourdomain.com
BASE_DOMAIN=yourdomain.com

# Authentication
JWT_SECRET=$JWT_SECRET
JWT_EXPIRY_HOURS=24
API_KEY_HMAC_SECRET=$API_KEY_HMAC_SECRET
TOTP_ENCRYPTION_KEY=$TOTP_ENCRYPTION_KEY

# Self-hosted mode
PLEXMCP_SELF_HOSTED=true
ENABLE_BILLING=false
ENABLE_SIGNUP=true

# Logging
RUST_LOG=info,plexmcp=debug
EOF

Run Migrations

# Install sqlx-cli if not already installed
cargo install sqlx-cli

# Run migrations
sqlx migrate run

Running Services

Systemd Service for API

Create /etc/systemd/system/plexmcp-api.service:

[Unit]
Description=PlexMCP API Server
After=network.target postgresql.service redis-server.service

[Service]
Type=simple
User=plexmcp
Group=plexmcp
WorkingDirectory=/opt/plexmcp
ExecStart=/opt/plexmcp/target/release/plexmcp-api
Restart=always
RestartSec=5
Environment=RUST_LOG=info,plexmcp=debug
EnvironmentFile=/opt/plexmcp/.env

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/plexmcp

[Install]
WantedBy=multi-user.target

Systemd Service for Frontend

Create /etc/systemd/system/plexmcp-web.service:

[Unit]
Description=PlexMCP Web Frontend
After=network.target plexmcp-api.service

[Service]
Type=simple
User=plexmcp
Group=plexmcp
WorkingDirectory=/opt/plexmcp/web
ExecStart=/usr/bin/node .next/standalone/server.js
Restart=always
RestartSec=5
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=HOSTNAME=0.0.0.0
EnvironmentFile=/opt/plexmcp/.env

# Security hardening
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Enable and Start Services

# Create plexmcp user
sudo useradd -r -s /bin/false plexmcp

# Set ownership
sudo chown -R plexmcp:plexmcp /opt/plexmcp

# Reload systemd
sudo systemctl daemon-reload

# Enable services
sudo systemctl enable plexmcp-api plexmcp-web

# Start services
sudo systemctl start plexmcp-api plexmcp-web

# Check status
sudo systemctl status plexmcp-api plexmcp-web

Reverse Proxy Setup

Nginx

Install and configure nginx:

sudo apt install -y nginx

Create /etc/nginx/sites-available/plexmcp:

# Rate limiting zone
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

server {
listen 80;
server_name yourdomain.com api.yourdomain.com;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name yourdomain.com;

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

# Frontend
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;
}
}

server {
listen 443 ssl http2;
server_name api.yourdomain.com;

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

# API with rate limiting
location / {
limit_req zone=api burst=20 nodelay;

proxy_pass http://127.0.0.1:8080;
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;

# SSE support
proxy_buffering off;
proxy_read_timeout 86400s;
}
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/plexmcp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

SSL with Let's Encrypt

# Install certbot
sudo apt install -y certbot python3-certbot-nginx

# Get certificate
sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com

# Auto-renewal is enabled by default
sudo systemctl status certbot.timer

Firewall Configuration

# Allow SSH, HTTP, HTTPS
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status

Monitoring

Log Viewing

# API logs
sudo journalctl -u plexmcp-api -f

# Web logs
sudo journalctl -u plexmcp-web -f

# Combined
sudo journalctl -u plexmcp-api -u plexmcp-web -f

Health Checks

# API health
curl http://localhost:8080/health

# Web health
curl http://localhost:3000/api/health

Resource Monitoring

# Process status
ps aux | grep plexmcp

# Memory usage
free -h

# Disk usage
df -h

Updating

See Upgrading Guide for update procedures.

Troubleshooting

API won't start

# Check logs
sudo journalctl -u plexmcp-api -n 50

# Common issues:
# - Database connection: verify DATABASE_URL
# - Port in use: check with `lsof -i :8080`
# - Permission denied: check file ownership

Database connection errors

# Test PostgreSQL connection
psql -h localhost -U plexmcp -d plexmcp -c "SELECT 1"

# Check PostgreSQL is running
sudo systemctl status postgresql

Redis connection errors

# Test Redis connection
redis-cli ping

# Check Redis is running
sudo systemctl status redis-server

Frontend build errors

# Clear cache and rebuild
cd web
rm -rf .next node_modules
npm install
npm run build

Next Steps