Skip to main content
This guide covers deploying Pala to production. Choose the deployment method that matches your needs and technical expertise.
Persistent Storage Required: Pala stores all data in a SQLite database and needs persistent disk storage to function. Traditional serverless platforms (Vercel, Netlify, Cloudflare Pages) have ephemeral file systems and won’t work.

Quick Deploy: Railway

The fastest way to deploy Pala to production.

Prerequisites

  • Railway account (free to start)
  • Domain name (optional, Railway provides a free subdomain)

Deployment Steps

1

Click deploy button

Deploy on Railway
2

Configure environment (optional)

Set environment variables if you want automated setup:
  • PALA_SUPERUSER_EMAIL
  • PALA_SUPERUSER_PASSWORD
  • PALA_APP_URL (optional, auto-detected)
3

Wait for deployment

Railway will:
  • Pull the Docker image
  • Create a persistent volume
  • Deploy the container
  • Generate a URL
4

Access your instance

Click the generated URL to access Pala. If you didn’t set environment variables, you’ll see the setup screen.
5

Configure custom domain (optional)

Railway Settings → Domains → Add custom domain
Cost: From $5/month (includes persistent volume)
Railway automatically handles SSL certificates, deployments, and scaling. Perfect for production use.

VPS Deployment

Deploy to any VPS for full control over your infrastructure.

Prerequisites

  • VPS with Docker installed (Hetzner, DigitalOcean, etc.)
  • SSH access to your server
  • Domain name pointed to your server IP
  • Basic command line knowledge
1

SSH into your server

ssh user@your-server-ip
2

Create project directory

mkdir palacms
cd palacms
3

Create docker-compose.yml

services:
  palacms:
    image: ghcr.io/palacms/palacms:latest
    restart: always
    ports:
      - "8080:8080"
    volumes:
      - palacms-data:/app/pb_data
    environment:
      - PALA_APP_URL=https://your-domain.com
      # Optional: automated setup
      # - PALA_SUPERUSER_EMAIL=admin@example.com
      # - PALA_SUPERUSER_PASSWORD=<secret>

volumes:
  palacms-data:
4

Start the container

docker-compose up -d
5

Verify it's running

docker-compose logs -f
You should see logs indicating the server started on port 8080.

Option 2: Docker Run

For simpler setups without compose:
docker run -d \
  --name palacms \
  --restart always \
  -p 8080:8080 \
  -v palacms-data:/app/pb_data \
  -e PALA_APP_URL=https://your-domain.com \
  ghcr.io/palacms/palacms:latest

Configure Reverse Proxy

Pala runs on port 8080. Use a reverse proxy for SSL and domain routing:
  • Nginx
  • Caddy
  • Traefik
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}
Get SSL certificates with Certbot:
sudo certbot --nginx -d your-domain.com

Platform-Specific Guides

Hetzner Cloud

Hetzner offers affordable VPS hosting in Europe and the US.
  1. Create a VPS (CX22 recommended: €4/month)
  2. Install Docker:
    curl -fsSL https://get.docker.com -o get-docker.sh
    sudo sh get-docker.sh
    
  3. Follow VPS deployment steps above
  4. Configure firewall to allow ports 80, 443, and 22

DigitalOcean

DigitalOcean provides simple VPS hosting with excellent documentation.
  1. Create a Droplet ($6/month minimum)
  2. Choose “Docker” from one-click apps (or install manually)
  3. Follow VPS deployment steps above
  4. Use DigitalOcean’s cloud firewalls for security

Fly.io

Fly.io offers a free tier with persistent volumes:
1

Install Fly CLI

curl -L https://fly.io/install.sh | sh
2

Login to Fly

fly auth login
3

Create fly.toml

app = "your-app-name"
primary_region = "sjc"

[build]
  image = "ghcr.io/palacms/palacms:latest"

[http_service]
  internal_port = 8080
  force_https = true

[[mounts]]
  source = "palacms_data"
  destination = "/app/pb_data"

[env]
  PALA_APP_URL = "https://your-app-name.fly.dev"
4

Create volume

fly volumes create palacms_data --size 3
5

Deploy

fly deploy

Database Backups

Pala uses SQLite, stored in /app/pb_data. Back up this directory regularly.
Cloud users: Backups are handled automatically. Backup frequency depends on your plan.
PocketBase has built-in automated backups that you can configure through the admin UI.
1

Access PocketBase Admin

Navigate to https://your-domain.com/_/ and log in with your admin credentials.
2

Go to Settings → Backups

Click on Settings in the sidebar, then select the Backups tab.
3

Configure backup schedule

Set a cron expression for your backup schedule:
  • Daily at 2 AM: 0 2 * * *
  • Every 6 hours: 0 */6 * * *
  • Hourly: 0 * * * *
  • Every minute (not recommended): * * * * *
4

Choose backup location

  • Local storage: Backups saved to /app/pb_data/backups
  • S3-compatible storage: Configure AWS S3, Backblaze B2, or similar for off-site backups
5

Set retention policy

Configure how many backups to keep (e.g., keep last 7 days of backups).
For production sites, configure S3-compatible storage for off-site backups. This protects against server failures.

Manual Backups with Docker

#!/bin/bash
# backup-palacms.sh

BACKUP_DIR="/backups/palacms"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Copy pb_data
docker cp palacms:/app/pb_data $BACKUP_DIR/pb_data_$DATE

# Keep only last 7 days
find $BACKUP_DIR -type d -mtime +7 -exec rm -rf {} +
Add to crontab:
0 2 * * * /path/to/backup-palacms.sh

Restore from Backup

# Stop container
docker-compose down

# Restore backup
docker cp pb_data_20250101_020000 palacms:/app/pb_data

# Start container
docker-compose up -d
Test your backups regularly. A backup you haven’t tested is not a backup.

Updating Pala

Docker Compose

# Pull latest image
docker-compose pull

# Restart with new image
docker-compose up -d

Docker Run

# Stop and remove old container
docker stop palacms
docker rm palacms

# Pull latest image
docker pull ghcr.io/palacms/palacms:latest

# Start new container (same command as initial deploy)
docker run -d --name palacms ...
Always backup before updating, especially for major version changes.

Performance Optimization

Enable Gzip Compression

In your reverse proxy: Nginx:
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
Caddy:
encode gzip

Add Caching Headers

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Use a CDN

Point your domain through Cloudflare (free tier) for:
  • Global CDN
  • DDoS protection
  • SSL certificates
  • Caching

Security Checklist

Generate random passwords for all accounts. Never use default or simple passwords.
Only allow ports 80, 443, and 22 (SSH). Block all other inbound traffic.
Regularly update Docker and the Pala image for security patches.
Never serve Pala over HTTP in production. Use Let’s Encrypt for free SSL certificates.
  • Disable password authentication
  • Use SSH keys only
  • Change default SSH port
  • Use fail2ban to block brute force attempts
Automate daily backups and store them off-server (S3, Backblaze, etc.).
Check Docker logs regularly for suspicious activity:
docker-compose logs -f --tail=100

Troubleshooting

See the Troubleshooting Guide for common deployment issues and solutions.

Next Steps