mirror of https://github.com/ghostfolio/ghostfolio
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
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
- Go to https://railway.app/new
- Click Deploy from GitHub repo
- Select your ghostfolio fork
- Select branch:
main - 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— PostgreSQLREDIS_HOST— Redis URLREDIS_PORT— Redis port
Redis auth note (important):
- Keep
REDIS_PASSWORDempty 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
Step 12: Setup nginx (Recommended)
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
- ✅ Deploy to Railway (fastest)
- ✅ Run smoke tests
- ✅ Record demo video
- 🔄 Update MVP-VERIFICATION.md with deployed URL
- 🔄 Later: Migrate to Hostinger VPS for production
Quick Reference
Railway:
- URL: https://railway.app
- CLI:
npm install -g @railway/cli - Docs: https://docs.railway.app
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.