Bagi developer mandiri, menyewa layanan cloud terkelola (seperti AWS RDS atau Managed Kubernetes) untuk proyek sampingan sering kali membebani biaya bulanan.
Dengan memanfaatkan Docker Compose dan Nginx Proxy Manager (atau Caddy), kita dapat mengorkestrasi puluhan aplikasi web, database PostgreSQL/MySQL, cache Redis, dan background queue worker di satu unit VPS Linux secara aman, terisolasi, dan hemat biaya.
graph TD
User[Internet Traffic] -->|Port 80 & 443| NPM[Nginx Proxy Manager / Ingress]
NPM -->|SSL Termination via Cloudflare| NPM
subgraph Isolated Docker Network: App-1
NPM -->|Internal Proxy: Port 8000| Web1[Laravel Octane / App 1]
Web1 --> DB1[(PostgreSQL 16 DB)]
Web1 --> RD1[(Redis 7)]
end
subgraph Isolated Docker Network: App-2
NPM -->|Internal Proxy: Port 3000| Web2[Node.js / React App 2]
Web2 --> DB2[(MySQL 8 DB)]
end
1. Prinsip Isolasi Jaringan (Docker Bridge Networks)
Kunci utama keamanan multi-container di satu VPS adalah jangan pernah mengekspos port database ke publik (0.0.0.0):
- Buat jaringan privat per aplikasi (misal
app1-network,app2-network). - Hanya container Ingress Reverse Proxy yang dihubungkan ke jaringan publik dan jaringan internal aplikasi.
- Port PostgreSQL (
5432) dan Redis (6379) hanya dapat diakses oleh container aplikasi di jaringan yang sama.
# Contoh docker-compose.production.yml
networks:
proxy-network:
external: true
internal-network:
driver: bridge
services:
app:
image: my-app:latest
networks:
- proxy-network
- internal-network
db:
image: postgres:16-alpine
networks:
- internal-network
# Tanpa 'ports' public mapping -> Terisolasi 100%
2. Otomasi Wildcard SSL via Cloudflare DNS Challenge
Menggunakan sertifikat SSL individual untuk setiap subdomain sering kali terbentur batas rate-limit Let’s Encrypt. Solusi terbaik adalah menerbitkan Wildcard SSL (*.domain.com):
- Gunakan integrasi DNS API Cloudflare Token di Nginx Proxy Manager.
- Sertifikat wildcard otomatis diperbarui secara berkala di background tanpa perlu membuka port 80 untuk challenge HTTP.
3. Strategi Health Check & Zero-Downtime Rollout
Tambahkan blok healthcheck pada setiap service untuk memastikan container pengganti benar-benar siap melayani request sebelum container lama dimatikan:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/up"]
interval: 10s
timeout: 5s
retries: 3