Cara Deploy Docker Container ke VPS dan Cloud Hosting Indonesia

Mengapa Deployment dengan Docker Lebih Unggul?
Setelah membangun aplikasi dan mengemas-nya ke dalam Docker image, langkah berikutnya adalah men-deploy ke server production. Deploy Docker container ke VPS menawarkan keunggulan signifikan dibanding deployment tradisional: tidak ada lagi masalah "aplikasi berjalan di lokal tapi error di server" karena container membawa seluruh environment-nya, rollback ke versi sebelumnya bisa dilakukan dalam hitungan detik, dan zero-downtime deployment dapat dicapai dengan strategi yang tepat.
Panduan cara deploy Docker ini mencakup alur kerja lengkap: dari membangun dan mempublish image ke registry, melakukan pull ke VPS production, mengatur Nginx sebagai reverse proxy, mengamankan dengan SSL, hingga mengotomasi proses deployment dengan CI/CD. Panduan ini mengasumsikan Anda sudah familiar dengan cara setup Docker di VPS dan Docker Compose.
Langkah 1: Membangun Docker Image untuk Production
Image production harus dioptimasi untuk keamanan dan ukuran. Gunakan multi-stage build di Dockerfile untuk memisahkan tahap build dan runtime:

# Dockerfile dengan multi-stage build untuk aplikasi Node.js
cat > Dockerfile << 'EOF'
# ---- Stage 1: Build ----
FROM node:20-alpine AS builder
WORKDIR /app
# Install dependencies (terpisah dari copy kode untuk cache efisiensi)
COPY package*.json ./
RUN npm ci --only=production
# Copy source code
COPY . .
# Build aplikasi (jika ada proses build seperti TypeScript)
RUN npm run build
# ---- Stage 2: Production Runtime ----
FROM node:20-alpine AS production
# Install dumb-init untuk proper signal handling
RUN apk add --no-cache dumb-init
# Jalankan sebagai user non-root untuk keamanan
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
WORKDIR /app
# Copy hanya artifacts yang dibutuhkan dari stage builder
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./
USER nodejs
EXPOSE 3000
ENV NODE_ENV=production
# dumb-init menangani signal (SIGTERM) dengan benar untuk graceful shutdown
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]
EOF
Build image dengan tag yang bermakna menggunakan format nama:versi atau nama:git-commit-hash:
# Build image production
docker build --target production -t myapp:1.0.0 .
docker build --target production -t myapp:$(git rev-parse --short HEAD) .
# Verifikasi ukuran image (multi-stage biasanya jauh lebih kecil)
docker images myapp
Langkah 2: Menggunakan Docker Registry
Registry adalah tempat menyimpan dan mendistribusikan Docker image. Ada beberapa opsi registry yang populer:
Opsi A: Docker Hub (Paling Mudah, Gratis untuk Public)
# Login ke Docker Hub
docker login
# Tag image dengan format username/nama-image:tag
docker tag myapp:1.0.0 usernameanda/myapp:1.0.0
docker tag myapp:1.0.0 usernameanda/myapp:latest
# Push ke Docker Hub
docker push usernameanda/myapp:1.0.0
docker push usernameanda/myapp:latest
Opsi B: GitHub Container Registry (Gratis, Terintegrasi dengan GitHub)
# Login menggunakan GitHub Personal Access Token
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Tag dan push ke GitHub Container Registry
docker tag myapp:1.0.0 ghcr.io/username/myapp:1.0.0
docker push ghcr.io/username/myapp:1.0.0
Opsi C: Self-Hosted Private Registry di VPS
Untuk kebutuhan privasi penuh, jalankan registry Docker sendiri di VPS:
# Jalankan Docker Registry resmi
docker run -d --name registry --restart unless-stopped -p 5000:5000 -v registry-data:/var/lib/registry registry:2
# Tag image untuk private registry
docker tag myapp:1.0.0 IP_VPS_ANDA:5000/myapp:1.0.0
# Push ke private registry
docker push IP_VPS_ANDA:5000/myapp:1.0.0
Langkah 3: Setup Nginx sebagai Reverse Proxy
Di production, container aplikasi tidak langsung diekspos ke internet. Nginx berfungsi sebagai reverse proxy yang menerima request dari internet dan meneruskannya ke container yang tepat:
# Buat direktori struktur project
mkdir -p ~/production/{nginx/conf.d,ssl}
cd ~/production
Buat konfigurasi Nginx untuk aplikasi:
cat > nginx/conf.d/myapp.conf << 'EOF'
# Redirect HTTP ke HTTPS
server {
listen 80;
listen [::]:80;
server_name aplikasi-anda.com www.aplikasi-anda.com;
# Challenge ACME untuk Let's Encrypt
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name aplikasi-anda.com www.aplikasi-anda.com;
ssl_certificate /etc/nginx/ssl/live/aplikasi-anda.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/aplikasi-anda.com/privkey.pem;
# Konfigurasi SSL yang aman
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# Proxy ke container aplikasi
location / {
proxy_pass http://app: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;
proxy_read_timeout 60s;
proxy_connect_timeout 10s;
}
# Static files langsung disajikan Nginx (lebih cepat)
location /static/ {
alias /var/www/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
Langkah 4: SSL Otomatis dengan Let's Encrypt dan Certbot
Integrasikan Certbot langsung ke dalam Docker Compose stack untuk manajemen SSL otomatis:
cat > docker-compose.yml << 'EOF'
version: "3.9"
services:
nginx:
image: nginx:1.25-alpine
container_name: prod-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./ssl:/etc/nginx/ssl:ro
- certbot-webroot:/var/www/certbot:ro
depends_on:
- app
networks:
- prod-net
app:
image: usernameanda/myapp:latest
container_name: prod-app
restart: unless-stopped
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=redis://redis:6379
depends_on:
- postgres
- redis
networks:
- prod-net
# Jangan expose port ke host - hanya accessible via Nginx
expose:
- "3000"
postgres:
image: postgres:16-alpine
container_name: prod-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- prod-net
redis:
image: redis:7-alpine
container_name: prod-redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- prod-net
certbot:
image: certbot/certbot:latest
container_name: prod-certbot
volumes:
- ./ssl:/etc/letsencrypt
- certbot-webroot:/var/www/certbot
# Hanya dijalankan saat perlu renew sertifikat
profiles:
- certbot
volumes:
postgres-data:
redis-data:
certbot-webroot:
networks:
prod-net:
driver: bridge
EOF
Jalankan stack dan dapatkan sertifikat SSL:
# Jalankan stack tanpa HTTPS terlebih dahulu
docker compose up -d
# Dapatkan sertifikat SSL (ganti domain dan email)
docker compose run --rm certbot certonly --webroot --webroot-path=/var/www/certbot -d aplikasi-anda.com -d www.aplikasi-anda.com --email admin@aplikasi-anda.com --agree-tos --no-eff-email
# Aktifkan konfigurasi HTTPS di Nginx dan reload
docker compose exec nginx nginx -s reload
Buat script auto-renewal sertifikat SSL:
cat > /usr/local/bin/renew-ssl.sh << 'EOF'
#!/bin/bash
cd /home/user/production
docker compose run --rm certbot renew --quiet
docker compose exec nginx nginx -s reload
EOF
chmod +x /usr/local/bin/renew-ssl.sh
# Jadwalkan cron untuk renew setiap hari pukul 03:00
echo "0 3 * * * /usr/local/bin/renew-ssl.sh >> /var/log/ssl-renew.log 2>&1" | crontab -

Langkah 5: Strategi Zero-Downtime Deployment
Update aplikasi tanpa downtime adalah kebutuhan production yang kritis. Berikut strategi yang bisa diterapkan di VPS single-server:
Strategi Blue-Green Deployment Sederhana
cat > /usr/local/bin/deploy.sh << 'EOF'
#!/bin/bash
set -e
APP_IMAGE="usernameanda/myapp"
NEW_VERSION=$1
COMPOSE_FILE="/home/user/production/docker-compose.yml"
if [ -z "$NEW_VERSION" ]; then
echo "Usage: $0 "
exit 1
fi
echo "=== Deploy versi $NEW_VERSION ==="
# Pull image versi baru
echo "Pulling image $APP_IMAGE:$NEW_VERSION..."
docker pull $APP_IMAGE:$NEW_VERSION
# Update environment variable image version
export APP_VERSION=$NEW_VERSION
cd /home/user/production
# Scale up dengan versi baru (pastikan ada 2 instance)
echo "Starting new container..."
docker compose up -d --scale app=2 --no-recreate
# Tunggu container baru siap (health check)
echo "Waiting for new container to be healthy..."
sleep 10
# Tag image sebagai latest
docker tag $APP_IMAGE:$NEW_VERSION $APP_IMAGE:latest
# Update stack ke versi baru dan scale kembali ke 1
docker compose up -d app
echo "=== Deploy selesai: $APP_IMAGE:$NEW_VERSION ==="
docker compose ps
EOF
chmod +x /usr/local/bin/deploy.sh
# Cara penggunaan:
# /usr/local/bin/deploy.sh 1.1.0
Langkah 6: Otomasi dengan CI/CD Pipeline
Otomasi proses build, test, dan deploy dengan GitHub Actions:
# Buat file .github/workflows/deploy.yml di repository Anda
mkdir -p .github/workflows
cat > .github/workflows/deploy.yml << 'EOF'
name: Build and Deploy
on:
push:
branches: [main]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout kode
uses: actions/checkout@v4
- name: Login ke Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build dan push Docker image
uses: docker/build-push-action@v5
with:
context: .
target: production
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy ke VPS via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
# Login ke registry
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
# Pull image terbaru
docker pull ghcr.io/${{ github.repository }}:latest
# Update dan restart service
cd ~/production
docker compose up -d --no-build app
# Verifikasi deployment berhasil
docker compose ps app
echo "Deployment selesai: $(date)"
EOF
Di GitHub repository Anda, tambahkan Secrets berikut di Settings > Secrets and variables > Actions: VPS_HOST (IP VPS), VPS_USER (username SSH), dan VPS_SSH_KEY (private key SSH dalam format PEM).
Langkah 7: Monitoring dan Observability di Production
Pantau kesehatan aplikasi Docker di production dengan stack monitoring sederhana:
cat > docker-compose.monitoring.yml << 'EOF'
version: "3.9"
services:
# Prometheus untuk metrics collection
prometheus:
image: prom/prometheus:latest
container_name: monitoring-prometheus
restart: unless-stopped
ports:
- "127.0.0.1:9090:9090" # Hanya accessible dari localhost
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
- monitoring-net
# Grafana untuk visualisasi dashboard
grafana:
image: grafana/grafana:latest
container_name: monitoring-grafana
restart: unless-stopped
ports:
- "127.0.0.1:3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana-data:/var/lib/grafana
networks:
- monitoring-net
# cAdvisor untuk Docker container metrics
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: monitoring-cadvisor
restart: unless-stopped
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
networks:
- monitoring-net
expose:
- "8080"
volumes:
prometheus-data:
grafana-data:
networks:
monitoring-net:
driver: bridge
EOF
# Jalankan monitoring stack
docker compose -f docker-compose.monitoring.yml up -d
Langkah 8: Backup Otomatis di Production
Pastikan data production selalu ter-backup secara otomatis:
cat > /usr/local/bin/docker-backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/var/backups/docker"
DATE=$(date +%Y%m%d_%H%M%S)
COMPOSE_DIR="/home/user/production"
mkdir -p $BACKUP_DIR
# Backup semua database PostgreSQL
docker exec prod-postgres pg_dumpall -U postgres | gzip > $BACKUP_DIR/postgres_$DATE.sql.gz
# Backup volume data penting menggunakan container sementara
docker run --rm -v production_postgres-data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/postgres-volume_$DATE.tar.gz /data
# Upload ke cloud storage (opsional - uncomment dan konfigurasi)
# aws s3 cp $BACKUP_DIR/postgres_$DATE.sql.gz s3://nama-bucket-anda/backups/
# Hapus backup lokal lebih dari 14 hari
find $BACKUP_DIR -type f -mtime +14 -delete
echo "Backup selesai: $DATE"
echo "Ukuran backup: $(du -sh $BACKUP_DIR)"
EOF
chmod +x /usr/local/bin/docker-backup.sh
# Jadwalkan backup harian pukul 02:30
echo "30 2 * * * /usr/local/bin/docker-backup.sh >> /var/log/docker-backup.log 2>&1" | crontab -
FAQ: Pertanyaan Umum tentang Deploy Docker di VPS
Apa perbedaan deploy Docker di VPS dan di shared hosting?
Shared hosting tidak mendukung Docker karena lingkungannya terbatas dan tidak memberikan akses kernel yang dibutuhkan container. Docker memerlukan VPS atau dedicated server dengan virtualisasi KVM yang memberikan akses penuh ke sistem operasi. VPS HostingEkspres berbasis KVM mendukung Docker sepenuhnya, sementara shared hosting tidak.
Berapa spesifikasi VPS minimum untuk menjalankan aplikasi Docker di production?
Spesifikasi minimum sangat bergantung pada aplikasi Anda. Sebagai panduan umum: untuk aplikasi web sederhana dengan satu container, VPS dengan 1 vCPU dan 1GB RAM sudah cukup. Untuk stack lengkap (app + database + cache + Nginx), disarankan minimal 2 vCPU dan 2GB RAM. Untuk aplikasi dengan traffic tinggi atau beberapa stack sekaligus, pilih 4 vCPU dan 4GB RAM atau lebih. Selalu monitor penggunaan resource dan upgrade jika CPU atau RAM secara konsisten melebihi 70-80%.
Bagaimana cara rollback ke versi sebelumnya jika deployment bermasalah?
Dengan Docker, rollback sangat mudah karena image lama masih tersimpan di registry. Cukup pull image versi lama dan restart container: docker pull usernameanda/myapp:1.0.0 && docker compose up -d. Pastikan Anda tidak pernah menghapus image production dari registry - selalu pertahankan minimal 3 versi terakhir untuk kemudahan rollback. Tag image menggunakan versi semantik atau git commit hash, bukan hanya latest.
Apakah bisa menjalankan beberapa website di satu VPS dengan Docker?
Ya, ini adalah salah satu keunggulan Docker. Anda bisa menjalankan beberapa website dengan domain berbeda di satu VPS menggunakan Nginx sebagai reverse proxy. Setiap website berjalan di container terpisah dengan port internal masing-masing, sementara Nginx mengarahkan request berdasarkan domain name ke container yang tepat. Semua website bisa memiliki SSL masing-masing melalui Let's Encrypt.
Bagaimana cara menangani environment variables yang berbeda antara staging dan production?
Gunakan file .env terpisah untuk setiap environment - .env.staging dan .env.production - dan panggil dengan flag --env-file: docker compose --env-file .env.production up -d. Untuk CI/CD, inject environment variables sebagai secrets di platform CI Anda (GitHub Actions secrets, dll) dan tulis ke file .env di VPS saat deployment, atau gunakan Docker Secrets untuk nilai yang paling sensitif.
Apakah Docker bisa digunakan bersama cPanel di VPS?
Secara teknis bisa, namun tidak direkomendasikan. cPanel mengambil banyak resource dan port sistem yang bisa konflik dengan container Docker. Lebih baik gunakan VPS yang didedikasikan untuk Docker tanpa cPanel. Jika membutuhkan antarmuka grafis untuk manajemen Docker, gunakan Portainer - tool manajemen Docker berbasis web yang ringan dan bisa dijalankan sebagai container itu sendiri.
Berapa lama proses deployment Docker ke VPS setelah setup awal selesai?
Setelah setup infrastruktur selesai (VPS, Docker, Nginx, SSL, dan CI/CD pipeline), setiap deployment berikutnya hanya memerlukan waktu 1–3 menit: sekitar 30–60 detik untuk build image di CI, 30–90 detik untuk pull image ke VPS (tergantung ukuran image dan kecepatan jaringan), dan beberapa detik untuk restart container. Dengan layer caching Docker yang optimal, waktu build bisa dipotong lebih jauh lagi.
Kesimpulan: Docker Deployment yang Profesional untuk Developer Indonesia
Panduan cara deploy Docker container ke VPS ini telah mencakup seluruh alur kerja deployment modern: dari membangun image production yang optimal dengan multi-stage build, mempublish ke registry, mengatur Nginx reverse proxy dengan SSL otomatis, menerapkan strategi zero-downtime deployment, hingga mengotomasi seluruh proses dengan CI/CD pipeline GitHub Actions.
Investasi waktu untuk menyiapkan infrastruktur Docker yang benar akan terbayar berlipat ganda dalam jangka panjang melalui deployment yang lebih cepat, lebih andal, dan lebih mudah di-maintain. Untuk mendukung deployment Docker production yang lancar, Anda membutuhkan VPS dengan performa dan stabilitas tinggi. VPS HostingEkspres berbasis KVM dengan SSD NVMe, uptime 99.9%, dan bandwidth besar adalah fondasi yang tepat untuk menjalankan aplikasi Docker Anda di Indonesia. Hubungi tim support HostingEkspres jika butuh bantuan setup awal Docker di VPS Anda.
Artikel Terkait

Cara Setup Docker di VPS: Panduan Containerization untuk Developer Indonesia
Panduan lengkap cara setup Docker di VPS Linux untuk developer Indonesia: instalasi Docker Engine, konfigurasi keamanan, menjalankan container pertama, manajemen image, hingga praktik terbaik containerization di production.
Baca Selengkapnya→
Tutorial Docker Compose: Cara Menjalankan Multi-Container Aplikasi
Tutorial Docker Compose lengkap dalam Bahasa Indonesia: cara menulis docker-compose.yml, menjalankan stack multi-container (web + database + cache), manajemen service, environment variables, hingga tips deployment production di VPS.
Baca Selengkapnya→
Cara Setup VPS Linux dari Nol: Panduan Lengkap untuk Pemula
Panduan lengkap cara setup VPS Linux dari nol untuk pemula: dari akses SSH pertama, konfigurasi keamanan dasar, instalasi web server Nginx, PHP, MySQL, hingga deploy website WordPress. Step-by-step dengan perintah lengkap.
Baca Selengkapnya→Butuh Hosting untuk Website Anda?
Dapatkan hosting cepat, aman, dan terpercaya dengan harga terjangkau. Gratis domain, SSL, dan support 24/7.
Jangan Ketinggalan Promo!
Subscribe newsletter kami dan dapatkan diskon hingga 50% untuk pembelian pertama kamu.
Gratis, tanpa spam. Bisa unsubscribe kapan saja.