HOSTING CEPATDOMAIN MURAHSSL GRATISSUPPORT 24/7UPTIME 99.9%SERVER INDONESIAHOSTING CEPATDOMAIN MURAHSSL GRATISSUPPORT 24/7UPTIME 99.9%SERVER INDONESIA
Tutorial

Cara Deploy Docker Container ke VPS dan Cloud Hosting Indonesia

Tim HostingEkspres|5 Juni 2026|15 menit baca
cara deploy dockerdeploy docker ke vpsdocker deployment indonesiadocker production vpsdocker registrycicd dockernginx docker reverse proxydeploy aplikasi docker
Cara Deploy Docker Container ke VPS dan Cloud Hosting Indonesia
📚 Baca juga: Cara Setup Vps | Cara Membuat Website | Cara Membuat Blog | Belajar Wordpress

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:

cara deploy docker
Ilustrasi cara deploy docker
# 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 -
cara deploy docker
Ilustrasi cara deploy docker

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.

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.