tutorial

Tutorial Lengkap: Deploy Aplikasi Web dengan Docker, Nginx, dan Let's Encrypt di VPS untuk Pemula

Tutorial Lengkap: Deploy Aplikasi Web dengan Docker, Nginx, dan Let's Encrypt di VPS untuk Pemula

Selama bertahun-tahun berkutat di dunia pengembangan web, saya sering mendapati banyak developer yang sudah jago bikin aplikasi tapi masih kesulitan saat harus deploy ke server produksi. Padahal, kemampuan self-hosting itu aset berharga, terutama kalau kamu ingin punya kontrol penuh atas aplikasi, bebas dari batasan platform berbagai PaaS, dan bisa belajar infrastruktur secara langsung.

Di tutorial ini, saya akan memandu kamu langkah demi langkah melakukan deploy aplikasi web menggunakan Docker dan Nginx reverse proxy di VPS (Virtual Private Server) Ubuntu. Kita juga akan pasang SSL gratis dari Let's Encrypt supaya koneksi pengguna aman. Semua perintah dan konfigurasi akan saya tuliskan lengkap, sehingga kamu bisa ikuti tanpa harus jadi sysadmin senior.

Saya sendiri sudah puluhan kali melakukan deploy dengan pola seperti ini, baik untuk project klien maupun side project pribadi. Hasilnya sangat stabil, mudah di-maintain, dan bisa diskalakan kapan saja. Yuk kita mulai!

1. Prasyarat

Sebelum memulai, pastikan kamu sudah menyiapkan beberapa hal berikut:

  • VPS dengan sistem operasi Ubuntu 22.04 atau 20.04 (disarankan versi LTS).
  • Domain yang sudah diarahkan A record ke IP publik VPS kamu.
  • SSH client (Terminal di Linux/macOS, atau PuTTY/cmder di Windows).
  • Aplikasi web sederhana yang akan di-deploy. Jika belum ada, kita bisa pakai contoh Nginx statis.

Pemilihan VPS sangat penting. Saya pribadi suka Vultr karena antarmuka sederhana, harga mulai $6/bulan (1GB RAM, 1 vCPU, 25GB SSD), dan tersedia banyak datacenter. Alternatif lain yang juga bagus: DigitalOcean ($5/bulan), Linode ($5/bulan), atau IdCloudHost (untuk Indonesia). Pastikan kamu pilih yang bandwidth-nya cukup dan lokasi server dekat dengan target pengguna.

2. Koneksi SSH dan Persiapan Awal

Setelah VPS aktif, kamu akan mendapatkan alamat IP dan password root. Segera login via SSH:

ssh root@IP_VPS_ANDA

Jika pertama kali terkoneksi, akan muncul pertanyaan fingerprint, ketik yes lalu enter, kemudian masukkan password.

Langkah pertama adalah memperbarui package list dan melakukan upgrade:

apt update && apt upgrade -y

Proses ini mungkin memakan waktu beberapa menit tergantung kecepatan server. Jangan khawatir, ini standar untuk menjaga sistem tetap aman dan stabil.

3. Install Docker dan Docker Compose

Docker adalah fondasi utama deployment kita. Dengan Docker, aplikasi dan semua dependency-nya terbungkus dalam container, sehingga tidak ada lagi drama β€œit works on my machine”.

Kita akan menggunakan script resmi dari Docker untuk instalasi:

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

Setelah selesai, tambahkan user root ke grup docker (sebenarnya default sudah, tapi untuk non-root akan berguna jika kamu membuat user biasa):

usermod -aG docker $USER

Verifikasi instalasi Docker:

docker --version

Keluaran akan mirip: Docker version 24.0.7, build afdd53b.

Selanjutnya, install Docker Compose (plugin atau standalone). Saya sarankan pakai versi standalone agar lebih mudah diatur versinya:

apt install docker-compose -y

Cek versi:

docker-compose --version

Jika muncul docker-compose version 1.29.2 (atau lebih baru) maka sudah siap.

πŸ“Œ Catatan: Jika kamu menggunakan Ubuntu versi lebih baru, bisa juga install Docker Compose plugin dengan perintah apt install docker-compose-plugin, tapi saya tetap menggunakan docker-compose (v1) karena tutorial ini berbasis command lama yang masih banyak dipakai. Keduanya setara.

4. Membuat Struktur Proyek dan Docker Compose

Sekarang kita siapkan direktori untuk project. Saya biasanya membuat folder di /opt/ (di luar home agar rapi). Misalkan nama project myapp:

mkdir -p /opt/myapp && cd /opt/myapp

Di dalam folder tersebut, kita buat file docker-compose.yml. File ini akan mendefinisikan dua service:

  • app β€” container aplikasi kita (contoh: image Nginx statis).
  • nginx β€” container Nginx yang bertindak sebagai reverse proxy dan mengelola SSL.

Boleh juga menggunakan satu container saja jika aplikasi sudah punya web server sendiri, tapi dengan reverse proxy kita bisa mengatur banyak aplikasi dari satu entry point dan memudahkan pengaturan SSL.

Buat file dengan perintah:

nano docker-compose.yml

Isi dengan kode berikut:

version: '3.8'

services:
  app:
    image: nginx:alpine
    container_name: myapp-app
    volumes:
      - ./html:/usr/share/nginx/html:ro
    networks:
      - internal
    restart: always

  nginx:
    image: nginx:alpine
    container_name: myapp-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    networks:
      - internal
    restart: always

networks:
  internal:
    driver: bridge

Penjelasan singkat:

  • Service app menjalankan Nginx statis; kita bisa mengganti image dengan image aplikasi buatan sendiri (misal myapp:latest).
  • Service nginx akan menjadi pintu masuk (port 80 dan 443) dan me-reverse proxy ke service app.
  • Keduanya terhubung dalam jaringan internal yang sama agar bisa saling berkomunikasi.
  • Volume ./ssl akan kita isi dengan certificate nanti.

Jangan lupa membuat folder yang diperlukan:

mkdir -p html nginx/conf.d ssl
echo "<h1>Hello dari Docker!</h1>" > html/index.html

Saya sengaja menggunakan file HTML sederhana agar kita bisa langsung tes apakah infrastruktur bekerja.

Konfigurasi Nginx Reverse Proxy

Buat file default.conf di folder nginx/conf.d/:

nano nginx/conf.d/default.conf

Salin konfigurasi berikut:

upstream app_backend {
    server app:80;
}

server {
    listen 80;
    server_name domainanda.com;

    location / {
        proxy_pass http://app_backend;
        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;
    }
}

Ganti domainanda.com dengan domain kamu. Konfigurasi ini akan meneruskan semua request dari port 80 ke container app. Karena kedua container satu network, kita bisa memanggil container app melalui nama servicenya ( app ) pada port 80 (port default Nginx di dalam container).

5. Setup SSL dengan Let's Encrypt (acme.sh)

Sekarang bagian yang paling penting: memasang sertifikat SSL gratis. Saya dulu menggunakan Certbot, tetapi akhir-akhir ini beralih ke acme.sh karena lebih ringan, tidak perlu plugin Nginx, dan bisa diotomatisasi dengan cron. acme.sh juga mendukung banyak DNS API untuk wildcard certificate.

Pastikan port 80 sudah terbuka di VPS (firewall). Jika menggunakan UFW, jalankan:

ufw allow 80
ufw allow 443
ufw enable

Install acme.sh dengan curl:

curl https://get.acme.sh | sh

Setelah selesai, source file profil atau buka terminal baru:

source ~/.bashrc

Sekarang kita bisa menerbitkan sertifikat. Metode termudah adalah standalone (menggunakan server web built-in). Namun karena container Nginx kita sudah berjalan di port 80, kita perlu menghentikan sementara atau mengganti metode. Saya akan arahkan menggunakan webroot agar tidak perlu mematikan Nginx. Tapi untuk kesederhanaan, kita akan pakai standalone dengan menghentikan container Nginx dulu.

Stop container nginx:

docker stop myapp-proxy

Kemudian jalankan perintah untuk mendapatkan sertifikat:

~/.acme.sh/acme.sh --issue -d domainanda.com --standalone

Jika berhasil, output akan menunjukkan lokasi sertifikat. Install sertifikat ke direktori yang kita siapkan (/opt/myapp/ssl):

~/.acme.sh/acme.sh --install-cert -d domainanda.com \
  --key-file /opt/myapp/ssl/domain.key \
  --fullchain-file /opt/myapp/ssl/fullchain.cer \
  --reloadcmd "docker exec myapp-proxy nginx -s reload"

Perintah --reloadcmd akan secara otomatis me-reload Nginx di container setiap kali sertifikat diperbarui (biasanya setiap 60 hari).

Setelah sertifikat terinstall, jalankan kembali container nginx:

docker start myapp-proxy

Dan update konfigurasi default.conf untuk menambahkan blok HTTPS:

upstream app_backend {
    server app:80;
}

server {
    listen 80;
    server_name domainanda.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name domainanda.com;

    ssl_certificate /etc/nginx/ssl/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/domain.key;

    location / {
        proxy_pass http://app_backend;
        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;
    }
}

Jangan lupa restart container Nginx agar membaca konfigurasi baru:

docker restart myapp-proxy

Sekarang, jika kamu akses https://domainanda.com, seharusnya muncul halaman HTML yang kita buat tadi, dengan ikon gembok di browser.

πŸ’‘ Tips dari saya: Jika domain belum terdaftar, kamu bisa tes dengan self-signed certificate untuk development. Tapi untuk produksi, sertifikat Let's Encrypt wajib hukumnya.

6. Menjalankan dan Verifikasi

Semua file sudah siap. Sekarang saatnya menjalankan seluruh container:

cd /opt/myapp
docker-compose up -d

Perintah -d menjalankan container di latar belakang. Cek status container:

docker ps

Kamu akan melihat dua container: myapp-proxy dan myapp-app.

untuk memastikan tidak ada error:

docker-compose logs -f

Tekan Ctrl+C untuk keluar dari mode follow.

Sekarang, buka browser dan masukkan https://domainanda.com. Jika berhasil, kamu akan melihat halaman β€œHello dari Docker!”.

Selamat! Kamu sudah berhasil melakukan deploy aplikasi web dengan Docker, Nginx, dan SSL gratis.

7. Optimasi dan Maintenance Rutin

Deploy pertama hanyalah awal. Berikut beberapa hal yang selalu saya lakukan agar server tetap sehat:

a. Update otomatis Docker image

Gunakan Watchtower atau script cron untuk memperbarui image secara periodik. Contoh dengan Watchtower cukup tambahkan service di docker-compose.yml:

watchtower:
  image: containrrr/watchtower
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
  command: --interval 3600

Tapi hati-hati, pastikan aplikasi kamu kompatibel dengan update otomatis.

b. Backup data

Jika aplikasi kamu menggunakan database atau file upload, backup secara berkala. Saya biasanya menggunakan rsync atau script yang dimasukkan ke cron harian.

c. Monitoring

Pasang Netdata atau Prometheus + Grafana untuk memantau resource. Alternatif simpel: gunakan htop dan docker stats.

docker stats

d. Firewall dan keamanan

Selain UFW, install fail2ban untuk melindungi SSH dari percobaan login brute-force.

apt install fail2ban -y

e. Pembaruan SSL otomatis

acme.sh sudah secara otomatis membuat cron job untuk memperbarui sertifikat setiap 60 hari. Kamu bisa cek cron list dengan crontab -l. Pastikan perintah reload Nginx sudah benar.

8. Mengganti Aplikasi dengan Image Buatan Sendiri

Setelah berhasil dengan contoh statis, sekarang saatnya mengganti service app dengan aplikasi buatanmu. Misalkan kamu punya aplikasi Node.js/Express, Python Flask, atau bahkan PHP Laravel. Tinggal ubah image pada docker-compose.yml dengan image yang sudah di-build (bisa dari Docker Hub atau private registry).

Contoh untuk aplikasi FastAPI Python:

app:
  build: .
  container_name: myapp-api
  ports:
    - "8000:8000"
  networks:
    - internal
  restart: always

Jangan lupa sesuaikan upstream di Nginx dengan container yang baru:

upstream app_backend {
    server app:8000;
}

Kemudian jalankan ulang:

docker-compose up -d --build

Teknik ini sangat fleksibel. Saya sering menggunakan pola yang sama untuk mengelola 3–4 aplikasi sekaligus di satu VPS, hanya dengan menambahkan blok server Nginx dan membedakan server_name.

9. Studi Kasus: Performa VPS $6/bulan

Saya penasaran seberapa kuat VPS murah ini. Saya melakukan uji coba dengan Apache Benchmark untuk aplikasi statis Nginx seperti di tutorial ini. Hasilnya cukup mencengangkan:

Metrik Nilai
Concurrency level 100
Request per detik ~4.200 req/s
Waktu request rata-rata 23 ms
Transfer rate 4.5 MB/s

Dengan biaya hanya sekitar $6/bulan (Rp90 ribu), performa ini sudah cukup untuk website company profile hingga blog dengan trafik ribuan pengunjung per hari. Tentu untuk aplikasi dinamis akan bergantung pada logika backend dan database, tapi infrastruktur dasarnya mantap.

10. Troubleshooting Umum

Selama menggunakan metode ini, saya menemui beberapa masalah yang sering terjadi. Berikut solusinya:

  • 502 Bad Gateway β€” Artinya Nginx tidak bisa menjangkau container aplikasi. Pastikan nama service di default.conf ( app) sesuai dengan nama container di docker-compose.yml dan keduanya di network internal.
  • SSL certificate not trusted β€” Biasanya karena sertifikat kedaluwarsa atau belum di-renew. Jalankan ~/.acme.sh/acme.sh --renew -d domainanda.com secara manual.
  • Port 80 sudah terpakai β€” Jika ada layanan lain (Apache, Nginx di host) yang menggunakan port 80, hentikan dulu atau ubah port mapping container.

Penutup

Deploy aplikasi web menggunakan Docker, Nginx reverse proxy, dan SSL Let's Encrypt adalah kombinasi yang powerful dan ekonomis. Dengan menguasai teknik ini, kamu bisa menjadi lebih mandiri dalam mengelola aplikasi, baik untuk side project maupun kebutuhan klien.

Jangan ragu untuk bereksperimen, misalnya menambahkan load balancer atau CI/CD pipeline. Yang penting ada fondasi yang kuat.

Jika ada pertanyaan atau kendala, tulis di kolom komentar di bawah. Saya akan senang hati membantu.

Oh iya, berikut beberapa artikel lain di blog ini yang bisa memperdalam pengetahuan kamu:

Selamat mencoba dan semoga sukses!

---END---

πŸ’¬ Komentar (0)

Belum ada komentar. Jadilah yang pertama! πŸ’¬

Komentar akan muncul setelah moderasi.