You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

11 KiB

Deployment Guide — Ghostfolio AI Agent

Two deployment options:

  • Railway — 5-minute setup, free tier, fastest for MVP
  • Hostinger VPS — Already paid, always-on, production-ready

Option A: Railway Deploy (5 minutes)

Prerequisites

  • GitHub repo with AI agent code
  • Railway account (free tier)
  • RAILWAY_API_KEY (optional, for CLI deployment)

Step 1: Prepare Repo

railway.toml already created in root:

[build]
builder = "NIXPACKS"

[deploy]
startCommand = "node main.js"
healthcheckPath = "/api/v1/health"
healthcheckTimeout = 300
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10

[env]
NODE_ENV = "production"
PORT = "3333"

Step 2: Push to GitHub

# Commit all changes
git add .
git commit -m "feat: add AI agent MVP with Railway deployment"
git push origin main

Step 3: Deploy via Railway UI

  1. Go to https://railway.app/new
  2. Click Deploy from GitHub repo
  3. Select your ghostfolio fork
  4. Select branch: main
  5. Railway auto-detects Node.js → Click Deploy

Step 4: Add Environment Variables

In Railway dashboard → Your Project → Variables:

Key Value
API_KEY_OPENROUTER sk-or-v1-...
OPENROUTER_MODEL anthropic/claude-3.5-sonnet
JWT_SECRET_KEY Generate: openssl rand -hex 32
ACCESS_TOKEN_SALT Generate: openssl rand -hex 32

Railway auto-provides:

  • DATABASE_URL — PostgreSQL
  • REDIS_HOST — Redis URL
  • REDIS_PORT — Redis port

Redis auth note (important):

  • Keep REDIS_PASSWORD empty unless your Redis instance explicitly requires password auth.
  • Railway-managed Redis often runs without password auth by default.
  • This project now handles empty password safely in Redis cache URL construction.

Step 5: Get Deployed URL

Railway provides URLs like:

https://your-app.up.railway.app
https://ghostfolio-ai-agent-production.up.railway.app

Step 6: Run Migrations

Railway console → Your service → New Console:

pnpm nx run api:prisma:migrate

Step 7: Test Deployed Endpoint

export GHOSTFOLIO_URL="https://your-app.up.railway.app"
export TOKEN="your-jwt-token-from-web-ui"

curl -X POST $GHOSTFOLIO_URL/api/v1/ai/chat \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "query": "Analyze my portfolio risk",
    "sessionId": "deploy-test"
  }'

Optional: Deploy via CLI

# Install Railway CLI
npm install -g @railway/cli

# Login
railway login --token $RAILWAY_API_KEY

# Init (creates railway project)
railway init

# Link to existing project
railway link

# Add PostgreSQL
railway add postgresql

# Add Redis
railway add redis

# Set environment variables
railway variables set API_KEY_OPENROUTER="sk-or-v1-..."
railway variables set OPENROUTER_MODEL="anthropic/claude-3.5-sonnet"
railway variables set JWT_SECRET_KEY="$(openssl rand -hex 32)"
railway variables set ACCESS_TOKEN_SALT="$(openssl rand -hex 32)"

# Deploy
railway up

# Open in browser
railway open

# View logs
railway logs

Railway Free Tier Limits

Resource Limit
RAM 512 MB
CPU Shared
Hours/month 500 hours ($5 free credit)
Sleep After 15 min inactivity
Cold start ~30 seconds

Workaround for sleep: Use external monitoring (UptimeRobot, Better Uptime) to ping every 5 min.


Option B: Hostinger VPS Deploy (1-2 hours)

Prerequisites

  • Hostinger VPS with SSH access
  • Domain name (optional, for SSL)
  • Basic Linux command line knowledge

Step 1: SSH into VPS

ssh root@your-vps-ip

Step 2: System Update

apt update && apt upgrade -y

Step 3: Install Node.js 22+

curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
node --version  # Should be v22+
npm --version

Step 4: Install pnpm

npm install -g pnpm

Step 5: Install PM2 (Process Manager)

npm install -g pm2

Step 6: Install PostgreSQL

apt install -y postgresql postgresql-contrib
systemctl enable postgresql
systemctl start postgresql

Setup database:

sudo -u postgres psql
CREATE DATABASE ghostfolio;
CREATE USER ghostfolio WITH PASSWORD 'your-secure-password';
GRANT ALL PRIVILEGES ON DATABASE ghostfolio TO ghostfolio;
ALTER USER ghostfolio CREATEDB;
\q

Step 7: Install Redis

apt install -y redis-server
systemctl enable redis-server
systemctl start redis-server

# Verify
redis-cli ping
# Should return: PONG

Step 8: Deploy Application

# Create app directory
mkdir -p /var/www
cd /var/www

# Clone your fork
git clone https://github.com/YOUR_USERNAME/ghostfolio.git
cd ghostfolio

# Or if pushing from local:
# git remote set-url origin git@github.com:YOUR_USERNAME/ghostfolio.git

# Install dependencies
pnpm install

# Build
pnpm build

# Run migrations
pnpm nx run api:prisma:migrate --prod

Step 9: Environment Variables

cat > .env <<'ENVEOF'
DATABASE_URL="postgresql://ghostfolio:your-secure-password@localhost:5432/ghostfolio"
REDIS_HOST=localhost
REDIS_PORT=6379
API_KEY_OPENROUTER=sk-or-v1-...
OPENROUTER_MODEL=anthropic/claude-3.5-sonnet
JWT_SECRET_KEY=$(openssl rand -hex 32)
ACCESS_TOKEN_SALT=$(openssl rand -hex 32)
NODE_ENV=production
PORT=3333
ENVEOF

# Secure the file
chmod 600 .env

Step 10: Start with PM2

# Start application
pm2 start dist/apps/api/main.js --name ghostfolio-api

# Save PM2 config
pm2 save

# Setup PM2 to start on boot
pm2 startup
# Run the command it outputs

# Check status
pm2 status
pm2 logs ghostfolio-api

Step 11: Configure Firewall

# Allow SSH
ufw allow 22/tcp

# Allow HTTP/HTTPS
ufw allow 80/tcp
ufw allow 443/tcp

# Allow app port (if accessing directly)
ufw allow 3333/tcp

# Enable firewall
ufw enable

# Check status
ufw status

Install nginx:

apt install -y nginx

Create config:

cat > /etc/nginx/sites-available/ghostfolio <<'NGINXEOF'
server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    location / {
        proxy_pass http://localhost:3333;
        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;
    }

    # Increase upload size if needed
    client_max_body_size 10M;
}
NGINXEOF

Enable site:

ln -s /etc/nginx/sites-available/ghostfolio /etc/nginx/sites-enabled/
nginx -t  # Test config
systemctl restart nginx

Step 13: SSL with Certbot (Free)

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

# Get SSL certificate
certbot --nginx -d your-domain.com -d www.your-domain.com

# Follow prompts, choose redirect to HTTPS

Auto-renewal is configured by default.

Step 14: Verify Deployment

# Check PM2
pm2 status

# Check logs
pm2 logs ghostfolio-api --lines 50

# Test locally
curl http://localhost:3333/api/v1/health

# Test from external
curl https://your-domain.com/api/v1/health

Step 15: Test AI Endpoint

export GHOSTFOLIO_URL="https://your-domain.com"
export TOKEN="your-jwt-token"

curl -X POST $GHOSTFOLIO_URL/api/v1/ai/chat \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "query": "Show my portfolio",
    "sessionId": "vps-test"
  }'

Hostinger VPS Maintenance

Update app:

cd /var/www/ghostfolio
git pull origin main
pnpm install
pnpm build
pm2 restart ghostfolio-api

View logs:

pm2 logs ghostfolio-api
pm2 monit  # Real-time monitoring

Restart:

pm2 restart ghostfolio-api
pm2 reload ghostfolio-api  # Zero-downtime

Database backup:

# Backup
pg_dump -U ghostfolio ghostfolio > backup_$(date +%Y%m%d).sql

# Restore
psql -U ghostfolio ghostfolio < backup_20260223.sql

Comparison Summary

Feature Railway Hostinger VPS
Setup time 5 min 1-2 hours
Cost Free tier / $5/m+ Already paid
Sleep Yes (15 min) No
SSL Auto (*.railway.app) Manual (Certbot)
Scaling Auto Manual
Control Limited Full
Best for MVP, demo Production

Health Check Endpoint

Both deployments expose:

GET /api/v1/health

Response:

{
  "status": "ok"
}

Troubleshooting

Railway: Build Fails

# Check build logs
railway logs --build

# Common fixes:
# - Ensure railway.toml is in root
# - Check NODE_ENV is set
# - Verify startCommand path is: node main.js

Railway: App Sleeps

# Use external monitoring:
# - UptimeRobot: https://uptimerobot.com
# - Better Uptime: https://betteruptime.com

# Ping every 5 minutes to keep alive

Railway: Slow API + Redis AUTH Errors

# Check logs for Redis auth spam
railway logs -s ghostfolio-api | grep "ERR AUTH"

# If logs show ERR AUTH and Railway Redis has no password auth:
# remove REDIS_PASSWORD from ghostfolio-api service vars
railway variable delete REDIS_PASSWORD -s ghostfolio-api -e production

# Redeploy after variable update
railway redeploy -s ghostfolio-api -y

VPS: PM2 Won't Start

# Check Node version
node --version  # Must be 22+

# Check if port in use
lsof -i :3333

# Check logs
pm2 logs --err

# Restart PM2
pm2 delete ghostfolio-api
pm2 start dist/apps/api/main.js --name ghostfolio-api

VPS: Database Connection Failed

# Verify PostgreSQL running
systemctl status postgresql

# Test connection
psql -U ghostfolio -h localhost -p 5432 -d ghostfolio

# Check DATABASE_URL in .env
echo $DATABASE_URL

VPS: Redis Connection Failed

# Verify Redis running
systemctl status redis-server

# Test connection
redis-cli ping

# Check Redis is listening
netstat -lntp | grep 6379

Common: Permission Denied

# Fix file permissions
chown -R $USER:$USER /var/www/ghostfolio
chmod -R 755 /var/www/ghostfolio

# Fix .env permissions
chmod 600 .env

Next Steps After Deployment

  1. Deploy to Railway (fastest)
  2. Run smoke tests
  3. Record demo video
  4. 🔄 Update MVP-VERIFICATION.md with deployed URL
  5. 🔄 Later: Migrate to Hostinger VPS for production

Quick Reference

Railway:

Hostinger VPS:

  • SSH: ssh root@ip
  • PM2: pm2 [start|stop|restart|logs]
  • nginx: /etc/nginx/sites-available/
  • SSL: certbot --nginx

Useful Commands:

# Railway
railway login
railway up
railway logs
railway open

# VPS
pm2 status
pm2 logs ghostfolio-api
systemctl status nginx
certbot renew --dry-run

Both options documented. Railway for speed, Hostinger for production.