Self-Hosting
Deploy your APSO backend on your own infrastructure for full control over your deployment.
Requirements
- Node.js 18+ (for TypeScript template)
- Python 3.10+ (for Python template)
- Go 1.21+ (for Go template)
- PostgreSQL 14+
- SSL certificate for production
Build for Production
TypeScript (NestJS)
# Install dependencies
npm ci --production=false
# Build
npm run build
# Start
NODE_ENV=production node dist/main.jsPython (FastAPI)
# Create virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Start with gunicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorkerGo (Gin)
# Build binary
CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server
# Start
./serverEnvironment Variables
# Required
DATABASE_URL=postgresql://user:pass@host:5432/db
JWT_SECRET=your-256-bit-secret
NODE_ENV=production
# Optional
PORT=3001
LOG_LEVEL=info
CORS_ORIGINS=https://yourapp.comDatabase Setup
PostgreSQL Installation
# Ubuntu/Debian
sudo apt install postgresql postgresql-contrib
# macOS
brew install postgresql@14
# Start service
sudo systemctl start postgresqlCreate Database
CREATE USER apso WITH PASSWORD 'your-password';
CREATE DATABASE apso_production OWNER apso;
GRANT ALL PRIVILEGES ON DATABASE apso_production TO apso;Connection Pooling
For production, use PgBouncer:
# /etc/pgbouncer/pgbouncer.ini
[databases]
apso_production = host=localhost port=5432 dbname=apso_production
[pgbouncer]
listen_port = 6432
listen_addr = 127.0.0.1
auth_type = md5
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20Reverse Proxy
Nginx
# /etc/nginx/sites-available/api.conf
upstream apso_backend {
server 127.0.0.1:3001;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name api.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;
location / {
proxy_pass http://apso_backend;
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;
}
}Caddy
# Caddyfile
api.yourdomain.com {
reverse_proxy localhost:3001
}Process Management
systemd
# /etc/systemd/system/apso.service
[Unit]
Description=APSO API Server
After=network.target postgresql.service
[Service]
Type=simple
User=apso
WorkingDirectory=/opt/apso
ExecStart=/usr/bin/node dist/main.js
Restart=on-failure
RestartSec=10
Environment=NODE_ENV=production
EnvironmentFile=/opt/apso/.env
[Install]
WantedBy=multi-user.target# Enable and start
sudo systemctl enable apso
sudo systemctl start apso
# View logs
sudo journalctl -u apso -fPM2
# Install PM2
npm install -g pm2
# Start application
pm2 start dist/main.js --name apso -i max
# Save configuration
pm2 save
pm2 startup
# Monitoring
pm2 monitecosystem.config.js
module.exports = {
apps: [{
name: 'apso',
script: 'dist/main.js',
instances: 'max',
exec_mode: 'cluster',
env_production: {
NODE_ENV: 'production',
PORT: 3001,
},
}],
};SSL Certificates
Let’s Encrypt
# Install certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d api.yourdomain.com
# Auto-renewal
sudo systemctl enable certbot.timerCloud Providers
AWS EC2
# Launch instance
aws ec2 run-instances \
--image-id ami-0123456789 \
--instance-type t3.medium \
--key-name your-key \
--security-group-ids sg-xxx
# Or use Elastic Beanstalk
eb init
eb create production
eb deployGoogle Cloud
# Create instance
gcloud compute instances create apso-server \
--machine-type=e2-medium \
--zone=us-central1-a
# Or use Cloud Run
gcloud run deploy apso \
--source . \
--platform managedDigitalOcean
# Create droplet via doctl
doctl compute droplet create apso \
--size s-2vcpu-4gb \
--image ubuntu-22-04-x64 \
--region nyc1Monitoring
Health Endpoint
// Kubernetes-style probes
@Get('/healthz')
healthz() {
return { status: 'ok' };
}
@Get('/readyz')
async readyz() {
await this.db.query('SELECT 1');
return { status: 'ready' };
}Prometheus Metrics
import { PrometheusModule } from '@willsoto/nestjs-prometheus';
@Module({
imports: [
PrometheusModule.register({
path: '/metrics',
defaultMetrics: { enabled: true },
}),
],
})
export class AppModule {}Security Checklist
- Firewall configured (only 80, 443 open)
- SSH key authentication only
- Database not exposed publicly
- Environment variables secured
- SSL/TLS enabled
- Rate limiting configured
- Security headers set
- Log rotation enabled
- Automated backups
- Monitoring alerts
Related
Last updated on