Scalable cloud infrastructure with Pulumi (Python), supporting frontend and backend deployments on UpCloud.
Internet
│
▼
[Load Balancer]
│
├─────────┬─────────┐
▼ ▼ ▼
[API-1] [API-2] [API-N] (Private Network)
│ │ │
└────┬────┴────┬────┘
│ │
▼ ▼
[Managed PostgreSQL] [Object Storage]
- Load Balancer: HTTP traffic distribution with health checks
- Cloud Servers: 2+ API application servers (scalable)
- Managed PostgreSQL: Fully managed database with automatic backups
- Object Storage: S3-compatible storage for images/files
- Private Network: Secure internal communication (10.0.0.0/24)
- Firewall: Security rules for network isolation
- Sign up at upcloud.com
- Create API credentials:
- Go to UpCloud Control Panel
- Navigate to: Account → API Access
- Click "Create API User" or use your account email
- Generate an API password (not your account password!)
- Save username and password securely
macOS:
brew install pulumiWindows:
choco install pulumiLinux:
curl -fsSL https://get.pulumi.com | shVerify installation:
pulumi versionPython 3.8+ required:
python3 --versioncd upcloud
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtChoose one option:
Option A: Pulumi Cloud (Free)
pulumi loginOption B: Local State
pulumi login --local# Initialize stack (typically use 'dev' or 'prod')
pulumi stack init devCopy example configuration:
cp Pulumi.dev.yaml.example Pulumi.dev.yamlEdit Pulumi.dev.yaml with your settings, or use CLI:
# Project settings
pulumi config set project_name myapp
pulumi config set environment production
pulumi config set zone de-fra1
# API servers
pulumi config set api_server_count 2
pulumi config set api_server_plan 2xCPU-4GB
# Database
pulumi config set database_plan 2x2xCPU-4GB
pulumi config set database_version 16
pulumi config set database_name appdb
pulumi config set database_username dbadmin
# UpCloud credentials (IMPORTANT: use --secret flag!)
pulumi config set upcloud:username your-upcloud-username
pulumi config set --secret upcloud:password your-upcloud-api-passwordPreview changes:
pulumi previewDeploy infrastructure:
pulumi upType yes when prompted to confirm deployment.
# View all outputs
pulumi stack output
# Get specific values
pulumi stack output load_balancer_endpoint
pulumi stack output database_host
# Get secrets (requires --show-secrets flag)
pulumi stack output database_password --show-secrets
pulumi stack output database_connection_string --show-secretsde-fra1- Frankfurt, Germany (default)fi-hel1- Helsinki, Finlandus-nyc1- New York, USAsg-sin1- Singaporenl-ams1- Amsterdam, Netherlands
1xCPU-2GB- Small (€15-20/month each)2xCPU-4GB- Medium (€30-35/month each) [Recommended]4xCPU-8GB- Large (€60-70/month each)8xCPU-16GB- X-Large (€120-140/month each)
1x1xCPU-2GB- Small (€30-40/month)2x2xCPU-4GB- Medium (€50-70/month) [Recommended]4x4xCPU-8GB- Large (€100-140/month)
# Increase to 4 servers
pulumi config set api_server_count 4
pulumi up# Upgrade to larger plan
pulumi config set database_plan 4x4xCPU-8GB
pulumi up# Upgrade to more powerful servers
pulumi config set api_server_plan 4xCPU-8GB
pulumi upNever commit secrets! Use Pulumi's secret management:
# Set secrets (encrypted in state)
pulumi config set --secret upcloud:password your-password
pulumi config set --secret api_key your-api-keyBuilt-in firewall rules:
- ✅ Allow HTTP (8080) from load balancer
- ✅ Allow SSH (22) for management
- ✅ Allow outbound HTTP/HTTPS
- ✅ Allow PostgreSQL (5432) to private network
- ❌ Drop all other inbound traffic
- Database is on private network only (no public access)
- API servers communicate internally via 10.0.0.0/24
- Only load balancer exposed to internet
Object storage requires manual setup in UpCloud Control Panel:
# View instructions
pulumi stack output object_storage_instructionsManual steps:
- Log into UpCloud Control Panel
- Go to Storage → Object Storage
- Create bucket (name from output:
object_storage_bucket_name) - Generate access keys
- Use S3-compatible client in your app
Example Python code:
import boto3
s3 = boto3.client('s3',
endpoint_url='https://de-fra1.upcloudobjects.com',
aws_access_key_id='YOUR_ACCESS_KEY',
aws_secret_access_key='YOUR_SECRET_KEY'
)
# Upload file
s3.upload_file('local.jpg', 'myapp-production-storage', 'images/file.jpg')
# Public URL
url = 'https://de-fra1.upcloudobjects.com/myapp-production-storage/images/file.jpg'# tests/test_infrastructure.py
import pulumi
import pytest
@pulumi.runtime.test
def test_api_server_count():
# Add your infrastructure tests
passRun tests:
pytest tests/View resource metrics in UpCloud Control Panel:
- CPU usage
- Memory usage
- Network traffic
- Database performance
Starting setup (2 API servers):
- 2x Cloud Servers (2xCPU-4GB): ~$60/month
- Managed PostgreSQL (2x2xCPU-4GB): ~$60/month
- Load Balancer: ~$15/month
- Object Storage: Pay-as-you-go (~$0.01/GB)
- Total: ~$135/month
Production setup (4 API servers):
- 4x Cloud Servers (4xCPU-8GB): ~$280/month
- Managed PostgreSQL (4x4xCPU-8GB): ~$140/month
- Load Balancer: ~$15/month
- Object Storage: ~$10-50/month
- Total: ~$445-485/month
# Pull latest changes
git pull
# Update dependencies
pip install -r requirements.txt --upgrade
# Preview changes
pulumi preview
# Apply updates
pulumi uppulumi stack history# View update history
pulumi stack history
# Rollback to specific version
pulumi stack select dev
pulumi refresh
# Manually revert code changes and run pulumi upWarning: This will delete all resources including databases!
# Preview what will be destroyed
pulumi destroy --preview-only
# Destroy everything
pulumi destroy# Verify credentials
pulumi config get upcloud:username
pulumi config get upcloud:password --show-secrets
# Update if needed
pulumi config set upcloud:username your-username
pulumi config set --secret upcloud:password your-passwordDatabase creation can take 15-30 minutes. If timeout occurs:
# Increase timeout or wait and refresh
pulumi refresh# Refresh state
pulumi refresh
# Cancel current update
pulumi cancel# Run with verbose logging
pulumi up --logtostderr -v=9- UpCloud Support: https://upcloud.com/support/
- Pulumi Community: https://slack.pulumi.com/
- ✅ Deploy infrastructure:
pulumi up - ✅ Get database credentials:
pulumi stack output database_connection_string --show-secrets - ✅ Set up object storage (see instructions output)
- 🎨 Deploy your frontend:
./deploy-frontend.sh(see FRONTEND_DEPLOYMENT.md) - 🔨 Deploy your API application to API servers
- 🌐 Configure DNS to point to load balancer and frontend
- 🔒 Set up SSL/TLS certificates
- 📊 Configure monitoring and alerts
- 🚀 Launch! � Frontend Deployment
This infrastructure supports hosting static frontends (SvelteKit, Next.js, Vite) via Object Storage:
Quick Deploy:
# Build your frontend
npm run build
# Deploy
./deploy-frontend.shSupported Frameworks:
- SvelteKit (static adapter)
- Next.js (static export)
- Vite (React, Vue, Svelte)
- Nuxt 3 (static generation)
See FRONTEND_DEPLOYMENT.md for complete guide including:
- Framework-specific configuration
- CI/CD setup (GitHub Actions)
- Custom domain configuration
- CDN integration
- Performance optimization
- ✅ Real Python - Use Python features (loops, functions, classes)
- ✅ Type Safety - IDE autocomplete and type checking
- ✅ Testing - Standard pytest framework
- ✅ Debugging - Use Python debugger
- ✅ Packages - Import any Python package
- ✅ Secrets - Built-in encrypted secret management
- ✅ Better Outputs - Rich, formatted outputs
- ✅ Component Resources - Create reusable components