Building a SaaS is expensive enough without hemorrhaging money on infrastructure. AWS bills can easily hit $500-1000/month for a simple app, and that's before you have paying customers.
This guide shows you how to build production-grade SaaS infrastructure for under €50/month—the same architecture that can handle 100K+ users. We'll cover the complete stack: compute, database, cache, storage, email, monitoring, and more.
The Budget SaaS Stack
| Component | Service | Cost/Month |
|---|---|---|
| Application Server | VPS (4GB RAM) | €8.99 |
| Database | PostgreSQL (on VPS) | €0 (included) |
| Cache | Redis (on VPS) | €0 (included) |
| Object Storage | S3-compatible | €3.99 |
| Email (Transactional) | Resend / Postmark | ~€0-20 |
| Monitoring | Uptime Kuma (self-hosted) | €0 |
| Error Tracking | Sentry (free tier) | €0 |
| Analytics | Plausible (self-hosted) | €0 (on same VPS) |
| SSL Certificates | Let's Encrypt | €0 |
| Domain | Any registrar | ~€1/mo |
| Total | €13-33/mo |
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└─────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Cloudflare (Free) │
│ DNS, DDoS Protection, CDN │
└─────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ VPS (€8.99/mo) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Caddy │ │
│ │ (Reverse Proxy + Auto SSL) │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴─────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ App │ │ Background │ │ Scheduler │ │ │
│ │ │ (Gunicorn/ │ │ Worker │ │ (Cron) │ │ │
│ │ │ PM2) │ │ (Celery/ │ │ │ │ │
│ │ │ │ │ Sidekiq) │ │ │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └─────────────┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ PostgreSQL │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Redis │ │ │
│ │ │ (Cache + Sessions + Queues) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ S3 Storage (€3.99/mo) │
│ User uploads, backups, assets │
└─────────────────────────────────────────────────────────────┘
Step 1: Provision Your VPS
Choosing the Right Size
| Stage | Expected Users | Recommended | Cost |
|---|---|---|---|
| MVP / Beta | 0 - 1,000 | 2 vCPU, 4GB RAM | €8.99/mo |
| Early Traction | 1,000 - 10,000 | 4 vCPU, 8GB RAM | €17.99/mo |
| Growth | 10,000 - 50,000 | Dedicated CPU or split services | €35-100/mo |
Initial Setup
# Create VPS on DanubeData
# Choose: Ubuntu 24.04, Standard plan (€8.99)
# SSH in
ssh root@your-server-ip
# Update system
apt update && apt upgrade -y
# Install essentials
apt install -y curl wget git ufw fail2ban
# Configure firewall
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# Create app user
adduser deploy
usermod -aG sudo deploy
Step 2: Install PostgreSQL
# Install PostgreSQL 16
apt install -y postgresql-16 postgresql-contrib-16
# Start and enable
systemctl enable postgresql
systemctl start postgresql
# Create database and user
sudo -u postgres psql << EOF
CREATE USER myapp WITH PASSWORD 'secure_password_here';
CREATE DATABASE myapp_production OWNER myapp;
GRANT ALL PRIVILEGES ON DATABASE myapp_production TO myapp;
c myapp_production
GRANT ALL ON SCHEMA public TO myapp;
EOF
# Test connection
psql -U myapp -d myapp_production -h localhost
PostgreSQL Tuning for SaaS
# /etc/postgresql/16/main/postgresql.conf
# Optimize for 4GB RAM VPS
# Memory
shared_buffers = 1GB
effective_cache_size = 3GB
work_mem = 16MB
maintenance_work_mem = 256MB
# Connections
max_connections = 100
# Write performance
wal_buffers = 64MB
checkpoint_completion_target = 0.9
# Query planning
random_page_cost = 1.1 # SSD storage
effective_io_concurrency = 200
# Reload config
sudo systemctl reload postgresql
Step 3: Install Redis
# Install Redis
apt install -y redis-server
# Configure Redis
cat >> /etc/redis/redis.conf << EOF
# Memory limit (leave room for app + PostgreSQL)
maxmemory 512mb
maxmemory-policy allkeys-lru
# Persistence (optional for cache-only use)
save 900 1
save 300 10
save 60 10000
EOF
# Restart Redis
systemctl restart redis-server
systemctl enable redis-server
# Test
redis-cli ping
# Should return: PONG
Step 4: Install Your Application
Example: Node.js SaaS
# Install Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
# Install PM2
npm install -g pm2
# Deploy app
su - deploy
cd ~
git clone https://github.com/youruser/your-saas.git app
cd app
npm ci --production
npm run build
# Create .env file
cat > .env << EOF
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://myapp:secure_password_here@localhost/myapp_production
REDIS_URL=redis://localhost:6379
SESSION_SECRET=$(openssl rand -hex 32)
EOF
# Start with PM2
pm2 start npm --name "saas-app" -- start
pm2 save
pm2 startup
Example: Laravel SaaS
# Install PHP 8.3
apt install -y php8.3-fpm php8.3-cli php8.3-pgsql php8.3-redis php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip
# Install Composer
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Deploy app
su - deploy
cd ~
git clone https://github.com/youruser/your-saas.git app
cd app
composer install --no-dev --optimize-autoloader
# Configure environment
cp .env.example .env
php artisan key:generate
# Edit .env
nano .env
# Set: DB_CONNECTION, DB_HOST, REDIS_HOST, etc.
# Run migrations
php artisan migrate --force
# Cache config
php artisan config:cache
php artisan route:cache
php artisan view:cache
Step 5: Set Up Reverse Proxy (Caddy)
# Install Caddy
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy
# Configure Caddy
cat > /etc/caddy/Caddyfile << 'EOF'
# Main application
app.yourdomain.com {
reverse_proxy localhost:3000 # Node.js
# OR for PHP:
# root * /home/deploy/app/public
# php_fastcgi unix//run/php/php8.3-fpm.sock
# file_server
encode gzip
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
Strict-Transport-Security "max-age=31536000; includeSubDomains"
}
}
# API subdomain (if separate)
api.yourdomain.com {
reverse_proxy localhost:3001
}
# Marketing site (optional)
www.yourdomain.com, yourdomain.com {
reverse_proxy localhost:3002
}
EOF
# Reload Caddy
systemctl reload caddy
Step 6: Set Up S3 Storage
# Create bucket on DanubeData
# Bucket name: yoursaas-uploads
# Install AWS CLI
apt install -y awscli
# Configure AWS CLI for DanubeData S3
aws configure
# Access Key: your-key
# Secret Key: your-secret
# Region: eu-central-1
# Output: json
# Add custom endpoint to ~/.aws/config
[default]
s3 =
endpoint_url = https://s3.danubedata.com
# Test
aws s3 ls s3://yoursaas-uploads/
Application Configuration
# .env (Node.js example)
S3_ENDPOINT=https://s3.danubedata.com
S3_BUCKET=yoursaas-uploads
S3_ACCESS_KEY=your-access-key
S3_SECRET_KEY=your-secret-key
S3_REGION=eu-central-1
# Laravel (.env)
FILESYSTEM_DISK=s3
AWS_ENDPOINT=https://s3.danubedata.com
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_DEFAULT_REGION=eu-central-1
AWS_BUCKET=yoursaas-uploads
AWS_USE_PATH_STYLE_ENDPOINT=true
Step 7: Transactional Email
Option 1: Resend (Recommended for Startups)
# Pricing: Free 3,000 emails/month, then $20/month for 50K
# Sign up at resend.com
# .env
RESEND_API_KEY=re_xxxxx
# Node.js example
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: 'hello@yourdomain.com',
to: user.email,
subject: 'Welcome to Our SaaS!',
html: 'Welcome aboard!
'
});
Option 2: Self-Hosted (Advanced)
# Use Postal for self-hosted email
# More complex but cheaper at scale
# Not recommended until 100K+ emails/month
Step 8: Monitoring Setup
Uptime Monitoring (Self-Hosted)
# Install Uptime Kuma on same VPS
docker run -d
--name uptime-kuma
-p 3001:3001
-v uptime-kuma:/app/data
--restart unless-stopped
louislam/uptime-kuma:1
# Add to Caddy
# status.yourdomain.com {
# reverse_proxy localhost:3001
# }
# Configure monitors for:
# - Main app (HTTPS)
# - API endpoints
# - Database (TCP check)
# - Redis (TCP check)
Error Tracking (Sentry)
# Sign up at sentry.io (free tier: 5K events/month)
# Node.js
npm install @sentry/node
// In your app
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: "https://xxx@sentry.io/xxx",
environment: process.env.NODE_ENV,
});
Log Management
# Simple: Use PM2 logs + logrotate
pm2 logs
# Better: Ship to free tier of Logtail, Papertrail, or Better Stack
# Advanced: Self-host Loki + Grafana (more resources needed)
Step 9: Automated Backups
#!/bin/bash
# /home/deploy/backup.sh
set -e
DATE=$(date +%Y-%m-%d_%H-%M-%S)
BACKUP_DIR="/home/deploy/backups"
S3_BUCKET="yoursaas-backups"
mkdir -p $BACKUP_DIR
# Backup PostgreSQL
pg_dump -U myapp myapp_production | gzip > "$BACKUP_DIR/db_$DATE.sql.gz"
# Backup Redis (if using persistence)
cp /var/lib/redis/dump.rdb "$BACKUP_DIR/redis_$DATE.rdb"
# Backup application config
tar -czf "$BACKUP_DIR/config_$DATE.tar.gz" /home/deploy/app/.env
# Upload to S3
aws s3 sync $BACKUP_DIR s3://$S3_BUCKET/ --endpoint-url https://s3.danubedata.com
# Clean up old local backups (keep 3 days)
find $BACKUP_DIR -type f -mtime +3 -delete
# Clean up old S3 backups (keep 30 days) - run weekly
# aws s3 ls s3://$S3_BUCKET/ --endpoint-url https://s3.danubedata.com | while read -r line; do
# # Delete files older than 30 days
# done
echo "Backup complete: $DATE"
# Add to crontab
crontab -e
# Daily backups at 3 AM
0 3 * * * /home/deploy/backup.sh >> /home/deploy/logs/backup.log 2>&1
Step 10: CI/CD Pipeline
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Deploy to VPS
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: deploy
key: ${{ secrets.VPS_SSH_KEY }}
script: |
cd ~/app
git pull origin main
npm ci --production
npm run build
pm2 restart saas-app
Scaling Path
When you outgrow the single VPS:
Stage 1: Vertical Scaling (Easiest)
- Upgrade to larger VPS (8GB → 16GB RAM)
- Still one server, minimal changes
- Good until ~50K users
Stage 2: Database Separation
- Move PostgreSQL to managed database (€19.99/mo)
- Add read replica for reporting queries
- App VPS focuses on application logic
Stage 3: Service Separation
- Separate VPS for background workers
- Managed Redis for cache (€9.99/mo)
- Load balancer for multiple app servers
Stage 4: Full Separation
- Multiple app servers behind load balancer
- Database with replicas
- Redis cluster
- CDN for static assets
Cost Comparison: AWS vs Budget Stack
| Component | AWS | Budget Stack |
|---|---|---|
| Compute | EC2 t3.medium: ~$30/mo | VPS: €8.99/mo |
| Database | RDS: ~$25-50/mo | On VPS: €0 |
| Cache | ElastiCache: ~$15/mo | On VPS: €0 |
| Storage | S3: ~$5-20/mo | S3: €3.99/mo |
| Load Balancer | ALB: ~$20/mo | Caddy: €0 |
| Data Transfer | ~$10-50/mo | 20TB included |
| Total | $105-185/mo | €13-33/mo |
| Annual | $1,260-2,220/yr | €156-396/yr |
Savings: $1,000-1,800/year—money you can spend on marketing, hiring, or runway.
Get Started Today
Ready to build your SaaS without breaking the bank?
- Create a VPS on DanubeData (€8.99/mo)
- Follow this guide to set up your stack
- Deploy your application
- Focus on building features, not managing infrastructure
DanubeData SaaS Starter Pack:
- VPS Standard: €8.99/mo (4GB RAM, 2 vCPU)
- S3 Storage: €3.99/mo (1TB included)
- Total: €12.98/mo for production-ready infrastructure
Need help architecting your SaaS infrastructure? Contact our team—we've helped dozens of startups launch.