Documentation Index
Fetch the complete documentation index at: https://mintlify.com/budgetron-org/budgetron/llms.txt
Use this file to discover all available pages before exploring further.
Budgetron can be self-hosted on any infrastructure that supports Docker or Node.js applications. This guide covers deployment options ranging from simple VPS setups to container orchestration platforms.
Prerequisites
Before deploying Budgetron, ensure you have:
- PostgreSQL Database (version 14 or higher)
- Node.js 20+ (if running without Docker)
- Docker (recommended for containerized deployments)
- 2GB RAM minimum (4GB recommended)
- 1 CPU core minimum (2+ recommended)
- 10GB storage (for application and database)
Deployment Options
Option 1: Docker on VPS
The simplest self-hosting approach using a Linux VPS.
1. Set Up PostgreSQL
Install PostgreSQL on your VPS:
# Ubuntu/Debian
sudo apt update
sudo apt install postgresql postgresql-contrib
# Start and enable PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql
Create a database and user:
CREATE DATABASE budgetron;
CREATE USER budgetron WITH PASSWORD 'secure_password';
GRANT ALL PRIVILEGES ON DATABASE budgetron TO budgetron;
ALTER DATABASE budgetron OWNER TO budgetron;
\q
2. Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
Log out and back in for group changes to take effect.
3. Create Environment File
Create a .env file with your configuration:
mkdir -p ~/budgetron
cd ~/budgetron
cat > .env << 'EOF'
DB_URL=postgres://budgetron:secure_password@localhost:5432/budgetron
AUTH_SECRET=$(openssl rand -base64 32)
AUTH_URL=https://budgetron.yourdomain.com
CRON_SECRET_SLUG=$(openssl rand -hex 16)
CRON_SECRET_TOKEN=$(openssl rand -hex 32)
# Optional: Google OAuth
# GOOGLE_CLIENT_ID=your-client-id
# GOOGLE_CLIENT_SECRET=your-client-secret
# Optional: AI Categorization
# OPENAI_COMPATIBLE_PROVIDER=ollama
# OPENAI_COMPATIBLE_BASE_URL=http://localhost:11434/v1
# OPENAI_COMPATIBLE_MODEL=llama3
# Optional: Email (Resend)
# EMAIL_PROVIDER_API_KEY=re_xxxx
# EMAIL_PROVIDER_FROM_EMAIL=noreply@yourdomain.com
EOF
Generate secure secrets:
sed -i "s/\$(openssl rand -base64 32)/$(openssl rand -base64 32)/" .env
sed -i "s/\$(openssl rand -hex 16)/$(openssl rand -hex 16)/" .env
sed -i "s/\$(openssl rand -hex 32)/$(openssl rand -hex 32)/" .env
4. Run Budgetron
docker run -d \
--name budgetron \
--restart unless-stopped \
--network host \
--env-file .env \
ghcr.io/budgetron-org/budgetron:latest
5. Set Up Reverse Proxy
Install and configure Nginx:
sudo apt install nginx certbot python3-certbot-nginx
Create Nginx configuration:
sudo nano /etc/nginx/sites-available/budgetron
server {
listen 80;
server_name budgetron.yourdomain.com;
location / {
proxy_pass http://localhost: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;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/budgetron /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Obtain SSL certificate:
sudo certbot --nginx -d budgetron.yourdomain.com
Option 2: Docker Compose Stack
Deploy Budgetron with all dependencies using Docker Compose.
Create docker-compose.yml:
version: '3.8'
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: budgetron
POSTGRES_USER: budgetron
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U budgetron"]
interval: 10s
timeout: 5s
retries: 5
networks:
- budgetron
app:
image: ghcr.io/budgetron-org/budgetron:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
DB_URL: postgres://budgetron:${DB_PASSWORD:-changeme}@postgres:5432/budgetron
AUTH_SECRET: ${AUTH_SECRET}
AUTH_URL: ${AUTH_URL}
CRON_SECRET_SLUG: ${CRON_SECRET_SLUG}
CRON_SECRET_TOKEN: ${CRON_SECRET_TOKEN}
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
OPENAI_COMPATIBLE_PROVIDER: ${OPENAI_COMPATIBLE_PROVIDER:-}
OPENAI_COMPATIBLE_BASE_URL: ${OPENAI_COMPATIBLE_BASE_URL:-}
OPENAI_COMPATIBLE_API_KEY: ${OPENAI_COMPATIBLE_API_KEY:-}
OPENAI_COMPATIBLE_MODEL: ${OPENAI_COMPATIBLE_MODEL:-}
EMAIL_PROVIDER_API_KEY: ${EMAIL_PROVIDER_API_KEY:-}
EMAIL_PROVIDER_FROM_EMAIL: ${EMAIL_PROVIDER_FROM_EMAIL:-}
BLOB_READ_WRITE_TOKEN: ${BLOB_READ_WRITE_TOKEN:-}
depends_on:
postgres:
condition: service_healthy
networks:
- budgetron
networks:
budgetron:
volumes:
postgres_data:
Create .env file:
DB_PASSWORD=secure_database_password
AUTH_SECRET=your_auth_secret_here
AUTH_URL=https://budgetron.yourdomain.com
CRON_SECRET_SLUG=your_slug
CRON_SECRET_TOKEN=your_token
Start the stack:
Option 3: Standalone Node.js
Run Budgetron without Docker.
1. Install Dependencies
# Install Node.js 20 via nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install 20
nvm use 20
# Install pnpm
npm install -g pnpm
2. Clone and Build
git clone https://github.com/budgetron-org/budgetron.git
cd budgetron
pnpm install
pnpm run build
cp .env.example .env
# Edit .env with your configuration
nano .env
4. Run Migrations
5. Start Server
# Development
pnpm run dev
# Production
pnpm run start
For production, use a process manager:
npm install -g pm2
pm2 start pnpm --name budgetron -- start
pm2 save
pm2 startup
Deploy to PaaS platforms with minimal configuration.
Railway
- Fork the Budgetron repository
- Create new project on Railway
- Add PostgreSQL database service
- Connect your GitHub repository
- Add environment variables in Railway dashboard
- Deploy automatically on push
Render
- Create new Web Service on Render
- Connect repository:
https://github.com/budgetron-org/budgetron
- Configure:
- Build Command:
pnpm install && pnpm run build
- Start Command:
pnpm start
- Add PostgreSQL database
- Set environment variables
- Deploy
Fly.io
Create fly.toml:
app = "budgetron"
primary_region = "iad"
[build]
image = "ghcr.io/budgetron-org/budgetron:latest"
[env]
PORT = "3000"
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
[[services]]
protocol = "tcp"
internal_port = 3000
[[services.ports]]
port = 80
handlers = ["http"]
[[services.ports]]
port = 443
handlers = ["tls", "http"]
Deploy:
fly launch
fly postgres create
fly secrets set AUTH_SECRET=$(openssl rand -base64 32)
fly secrets set AUTH_URL=https://budgetron.fly.dev
fly secrets set CRON_SECRET_SLUG=$(openssl rand -hex 16)
fly secrets set CRON_SECRET_TOKEN=$(openssl rand -hex 32)
fly deploy
Database Management
Backups
Automate PostgreSQL backups:
#!/bin/bash
# /usr/local/bin/backup-budgetron.sh
BACKUP_DIR="/var/backups/budgetron"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
pg_dump -U budgetron budgetron | gzip > $BACKUP_DIR/budgetron_$DATE.sql.gz
# Keep last 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
Schedule with cron:
0 2 * * * /usr/local/bin/backup-budgetron.sh
Restore from Backup
gunzip -c /var/backups/budgetron/budgetron_20260305_020000.sql.gz | \
psql -U budgetron budgetron
Updates and Maintenance
Updating Docker Deployment
# Pull latest image
docker pull ghcr.io/budgetron-org/budgetron:latest
# Stop and remove old container
docker stop budgetron
docker rm budgetron
# Start new container with same configuration
docker run -d \
--name budgetron \
--restart unless-stopped \
--network host \
--env-file .env \
ghcr.io/budgetron-org/budgetron:latest
Updating Docker Compose
docker compose pull
docker compose up -d
Updating Standalone
cd ~/budgetron
git pull origin master
pnpm install
pnpm run build
pnpm run db:migrate
pm2 restart budgetron
Monitoring
Container Logs
# Docker
docker logs -f budgetron
# Docker Compose
docker compose logs -f app
# PM2
pm2 logs budgetron
Resource Usage
# Docker stats
docker stats budgetron
# System resources
htop
Application Health
Check if the application is responding:
curl http://localhost:3000
Troubleshooting
Database Connection Issues
Verify PostgreSQL is running:
sudo systemctl status postgresql
psql -U budgetron -d budgetron -h localhost
Container Won’t Start
Check logs for errors:
Common issues:
- Invalid
DB_URL format
- Database not accessible
- Missing required environment variables
Port Already in Use
Find and kill the process:
sudo lsof -i :3000
sudo kill -9 <PID>
Migration Failures
Run migrations manually:
# Docker
docker exec -it budgetron sh
node drizzle/migrate/migrate.cjs \
--db-url="$DB_URL" \
--migrations-folder="drizzle/migrations"
# Standalone
pnpm run db:migrate
Security Considerations
- Use strong, unique passwords for database and auth secrets
- Keep PostgreSQL on localhost or private network
- Enable SSL/TLS for all external connections
- Regularly update Budgetron and dependencies
- Use firewall to restrict access (ufw, iptables)
- Enable automatic security updates on your VPS
See Production Setup for comprehensive security hardening.
Next Steps