Troubleshooting GCP
5. Deployment (Modul 5)
Section titled “5. Deployment (Modul 5)”| Gejala | Penyebab | Solusi cepat |
|---|---|---|
| Tidak bisa daftar GCP | tidak punya kartu kredit | pakai project bersama panitia (lihat §7) |
| SSH-in-Browser gagal | belum Authorize / firewall / API | klik Authorize; cek rule default-allow-ssh; enable Compute Engine API |
permission denied ... docker daemon |
grup docker belum aktif | exit lalu SSH ulang setelah sudo usermod -aG docker $USER |
| Cloud Build gagal di step 3 (SSH) | 4 role IAM belum ditambah | tambahkan Compute Instance Admin (v1), Compute OS Login, IAP-secured Tunnel User, Service Account User |
| Build sukses tapi web tidak berubah | container belum restart | docker compose pull nextjs && docker compose up -d nextjs; cek docker compose logs nextjs |
docker compose up -d manual di VM gagal dengan error from registry: Unauthenticated request. Unauthenticated requests do not have permission "artifactregistry.repositories.downloadArtifacts" |
Docker tidak mengirim kredensial sama sekali (HTTP 401), jadi ini bukan kekurangan role. Kredensial Artifact Registry disimpan per pengguna di ~/.docker/config.json. Trigger Cloud Build menjalankan gcloud auth configure-docker sebelum pull, sehingga perintah manual dari user OS Login tidak mewarisi kredensial itu; login memakai access token juga hanya berlaku 60 menit. Pesan yang benar-benar masalah role berbunyi Permission 'artifactregistry.repositories.downloadArtifacts' denied tanpa kata “Unauthenticated” |
Periksa lebih dahulu isi ~/.docker/config.json dan sudo cat /root/.docker/config.json (ada credHelpers atau auths untuk asia-southeast2-docker.pkg.dev?) serta gcloud auth list. Bila kedua berkas itu tidak ada, kredensial memang belum pernah dibuat di VM tersebut. Pada VM panduan ini, gcloud auth list menampilkan <PROJECT_NUMBER>-asisten01@example.com sebagai akun ACTIVE karena gcloud memakai identitas VM dari metadata server, jadi tidak perlu login: cukup gcloud auth configure-docker asia-southeast2-docker.pkg.dev, lalu docker compose pull. Jalankan gcloud auth login hanya bila tidak ada akun berstatus ACTIVE. Docker sebagai root: gcloud auth print-access-token | sudo docker login -u oauth2accesstoken --password-stdin https://asia-southeast2-docker.pkg.dev, lalu sudo -H docker compose up -d. Token root kedaluwarsa dalam 60 menit, jadi login ulang sebelum pull manual berikutnya; cara yang tidak perlu login ulang adalah memakai trigger Cloud Build. Bila setelah itu pesannya berubah menjadi not found, artinya autentikasi sudah berhasil, sebab registry baru dapat menjawab begitu identitasnya dikenali. Berarti nama image di .env atau compose tidak ada di repository. Samakan namanya dengan hasil build (konvensi project kelompok: nextjs-<slug>), periksa dengan: gcloud artifacts docker images list asia-southeast2-docker.pkg.dev/<PROJECT_ID>/katalog-images |
cd ~/app: No such file di Cloud Build |
SSH dari service account punya home berbeda | ubah cd ~/app → cd /home/<user-vm>/app (Modul 6.1 F) |
| Domain belum resolve | propagasi DNS | nslookup <domain>; TTL 5 menit; tunggu |
Certbot Timeout during connect |
port 80 tertutup / A record salah | cek firewall GCP Allow HTTP traffic; cek A record |
bind: address already in use port 80 |
nginx host vs nginx container | sudo systemctl stop nginx && sudo systemctl disable nginx |
| Domain terbuka dari ponsel atau Cloud Shell tetapi dari laptop menampilkan halaman aplikasi lain, misalnya Nginx Proxy Manager | Resolver DNS lokal mengarahkan seluruh subdomain ke server lain. Wildcard seperti *.domain.com menuju homeserver menang atas record publik selama perangkat memakai resolver itu |
Bandingkan dua resolver sebelum menyalahkan recordnya: dig +short NAMA lalu dig +short NAMA @1.1.1.1. Kalau hasilnya berbeda, masalahnya di jaringan lokal. Untuk menguji VM-nya sendiri, paksa alamatnya dengan curl -sS -o /dev/null -w "ip=%{remote_ip} kode=%{http_code}\n" --resolve NAMA:443:IP_VM https://NAMA/portal/. Balasan 200 berarti VM sehat |
| Katalog 2D atau 3D gagal saat menambah data, padahal login berhasil | Fitur katalog memerlukan sebelas variabel tambahan yang tidak dipakai fitur lain, yaitu POSTGIS_* untuk koneksi langsung ke PostGIS dan GEOSERVER_* untuk memanggil REST API GeoServer |
Isi variabelnya pada .env, lalu sudo docker compose up -d nextjs. Nama lengkapnya ada pada .env.example di repository acuan. Halaman portal publik, GeoServer, dan WFS tetap berjalan tanpa variabel ini |
Login membalas pesan Prisma You must provide a nonempty URL. The environment variable DATABASE_URL resolved to an empty string |
DATABASE_URL pada .env masih kosong, sehingga Prisma tidak punya alamat database |
Bukan kerusakan. Isi DATABASE_URL dengan connection string dari Modul 4, lalu jalankan sudo docker compose up -d nextjs. Selama kosong, build, halaman portal publik, GeoServer, dan seluruh jalur HTTPS tetap berjalan normal |
fatal: detected dubious ownership in repository at '/opt/webgis/app' |
Direktori aplikasi dimiliki pengguna lain, biasanya root karena clone atau pembuatan direktorinya dijalankan memakai sudo |
Perbaiki kepemilikannya, jalankan di dalam VM: sudo chown -R "$USER:$USER" /opt/webgis/app. Menambahkan safe.directory lewat git config hanya membungkam peringatannya dan tidak mengembalikan izin tulis, sehingga git pull berikutnya tetap gagal |
| Push tidak memicu build walaupun trigger terlihat ada di daftar | Trigger tidak terhubung ke repository. Trigger generasi pertama memakai kolom github, generasi kedua memakai repositoryEventConfig. Keduanya bisa dipakai, tetapi trigger tanpa keduanya tidak akan menyala dari push |
Periksa dengan gcloud builds triggers describe NAMA_TRIGGER --region=REGION. Buktikan dengan satu push kosong sebelum mengandalkannya, jangan hanya melihat trigger ada di daftar |
| VM kelima atau keenam ditolak dengan pesan kuota | Kuota IN_USE_ADDRESSES hanya 4 alamat IPv4 eksternal per region, sedangkan setiap VM memakai satu |
Buat VM berikutnya dengan --no-address lalu akses lewat terowongan IAP, atau taruh di region lain. Membagi zone di region yang sama tidak menambah jatah |
ERR_CONNECTION_REFUSED saat membuka localhost:8080 lewat terowongan IAP |
Terowongan dijalankan di Cloud Shell, sedangkan browser dibuka di laptop. Keduanya punya localhost yang berbeda |
Jalankan gcloud compute start-iap-tunnel di komputer yang dipakai membuka browser. Untuk memeriksa tanpa browser, jalankan terowongan di satu tab Cloud Shell lalu curl dari tab kedua |
| Login gagal padahal halaman peta terbuka lewat terowongan | NEXTAUTH_URL dan BASE_URL menunjuk ke alamat IP, sedangkan browser memakai localhost |
Isi NEXTAUTH_URL dan BASE_URL dengan http://localhost:8080/portal, lalu pakai nomor port terowongan yang sama untuk semua orang |
Kuota CPUS tidak berubah setelah VM dibuat |
Nilai kuota CPU diperbarui beberapa menit setelah VM berjalan, sedangkan INSTANCES dan kuota disk langsung berubah |
Tunggu beberapa menit lalu baca ulang. Jangan menyimpulkan bobot vCPU dari selisih yang terbaca terlalu cepat |
| Kenaikan kuota ditolak, formulir menolak nilai di atas batas | Riwayat pemakaian project belum mencukupi, bukan karena jenis billing account | Rancang di dalam batas yang ada, lalu coba ajukan lagi setelah project punya riwayat pemakaian. Rincian angkanya ada pada panduan deployment bagian 10 |
6b. GeoServer di VM: memori, unggah data, dan kata sandi
Section titled “6b. GeoServer di VM: memori, unggah data, dan kata sandi”Bagian ini disusun dari pengujian nyata pada satu VM e2-medium tanggal 11 September 2026,
ditambah analisis konfigurasi. Kolom Status menyatakan seberapa jauh setiap baris sudah
dibuktikan. Baris yang masih berupa dugaan perlu diuji di VM sendiri lewat
workbook asisten trainer.
| Gejala | Penyebab | Solusi cepat | Status |
|---|---|---|---|
geoserver_app berstatus Exited (137) dan mati sendiri |
Dugaan awal menyebut memori habis pada e2-medium 4 GB, tetapi pengukuran tidak membuktikannya |
Periksa docker inspect --format '{{.State.OOMKilled}}' geoserver_app lebih dahulu. Kalau false, memori bukan penyebabnya. Kalau true, turunkan MAXIMUM_MEMORY dari 2048m ke 1024m, lalu docker compose up -d geoserver |
Terukur, sebab awal tidak terbukti |
| VM terasa berat saat GeoServer boot | Dugaan awal menyebut heap 2 GB tidak muat di VM 4 GB. Pengukuran tidak membuktikannya, karena pemakaian GeoServer hanya 882 MiB | Catat free -h dan docker stats --no-stream. Dengan tiga container berjalan, 2,3 GiB dari 3,8 GiB masih tersedia, jadi heap 2048m tidak perlu diturunkan lebih dahulu |
Terukur, 882 MiB dari batas 2048 MiB |
Halaman /geoserver/web menampilkan 502 |
Dua sebab berbeda: GeoServer belum selesai boot, atau Nginx tidak memuat rute /geoserver/ |
Tunggu sampai log GeoServer memuat Server startup in [...] milliseconds, terukur sekitar 47 detik. Kalau 502 menetap, periksa docker compose ps dan pastikan nginx_proxy berstatus running, lalu pastikan nginx.conf pada clone VM memuat blok location /geoserver/ |
Terbukti saat pengujian |
GeoServer minta admin / geoserver padahal sudah diganti |
Kata sandi hasil perubahan lewat antarmuka web tidak bertahan | Isi GEOSERVER_ADMIN_PASSWORD pada docker-compose.yml. Tanpa variabel itu, image membuat kata sandi acak baru setiap container dijalankan dan menuliskannya pada log startup |
Terbukti dari dokumentasi image |
| Layer hilang setelah container di-restart | Volume ./geoserver-data tidak terpasang, atau container dihapus dengan -v |
Periksa docker compose config dan pastikan volume menunjuk ke /opt/geoserver/data_dir. Jalankan docker compose down tanpa -v. Dengan volume itu, layer hasil unggahan terbukti bertahan setelah docker compose restart geoserver |
Terbukti saat pengujian |
JAVA_OPTS pada modul tidak berpengaruh |
Image kartoza/geoserver membaca INITIAL_MEMORY dan MAXIMUM_MEMORY, bukan JAVA_OPTS |
Ganti nama variabelnya pada docker-compose.yml |
Terbukti dari dokumentasi image |
| Permintaan WMS membalas halaman login, bukan gambar | ROLE_ANONYMOUS belum diberi izin Read |
Tab Security pada layer, aktifkan Read untuk ROLE_ANONYMOUS |
Terbukti dari perilaku GeoServer |
ServiceException tentang layer tidak ditemukan |
Nama workspace atau nama layer salah pada permintaan WFS | Periksa daftar Layers, lalu pakai format workspace:nama_layer |
Terbukti dari perilaku GeoServer |
| Store GeoJSON tidak ada di daftar Data Source | Image kartoza/geoserver:2.24.1 tidak memuat plugin GeoJSON. Store CSV bisa dibuat, tetapi kolom WKT-nya terbaca sebagai String sehingga muncul bounding box boundary values are invalid |
Unggah data sebagai Shapefile dengan Data Source Name sama dengan nama berkas, misalnya batas_admin. Inilah jalur yang terbukti |
Terbukti saat pengujian |
Endpoint API membalas 308 padahal alamatnya sudah benar |
Ini terjadi pada aplikasi yang memakai trailingSlash: true. Sejak repository instruktur disinkronkan pada 12 September 2026, trailingSlash tidak dipakai lagi, sehingga permintaan API tanpa slash dilayani langsung |
Tidak berlaku lagi untuk konfigurasi sekarang. Kalau kamu masih melihat 308 pada endpoint API, periksa next.config.mjs: kemungkinan masih ada trailingSlash: true dari versi lama |
Tidak lagi berlaku sejak 12 September 2026 |
/geoserver/web/ mengalihkan ke /geoserver/web |
GeoServer memakai bentuk tanpa slash sebagai jalur kanonik | Pakai http://IP_EKSTERNAL_VM/geoserver/web tanpa slash di akhir. Sejak 12 September 2026, /portal juga tanpa slash, jadi aturannya kini sama untuk keduanya |
Terbukti saat pengujian |
GeoServer menampilkan peringatan The master password for this server has not been changed from the default |
Master password adalah kata sandi terpisah untuk enkripsi konfigurasi, bukan kata sandi login admin. Mengganti GEOSERVER_ADMIN_PASSWORD tidak mengubahnya |
Peringatan ini tidak menghalangi login. Verifikasi pengamanan dengan tiga perintah di bawah, bukan dari peringatan itu | Terbukti saat pengujian |
nginx_proxy keluar dengan kode 1, dan port 80 membalas Connection refused |
Nginx menyelesaikan nama service saat start, sedangkan container nextjs belum ada sebelum Cloud Build pertama. Pesan host not found in upstream hanya muncul di log container, bukan di browser |
Pindahkan alamat tujuan ke variabel dan tambahkan resolver 127.0.0.11 valid=10s ipv6=off pada tiap blok location, lalu proxy_pass $variabel. Penyelesaian nama jadi ditunda sampai ada permintaan |
Terbukti saat pengujian |
required variable NEXTJS_IMAGE is missing a value pada docker compose up -d geoserver nginx |
Compose membaca seluruh berkas sebelum memilih service, jadi variabel kosong menggagalkan semua perintah, bukan hanya service nextjs |
Isi NEXTJS_IMAGE dengan image yang benar-benar ada, misalnya nginx:1.27-alpine. Cloud Build menimpanya dengan tag asli setelah build pertama |
Terbukti saat pengujian |
pull access denied for <nama>, repository does not exist lalu geoserver dan nginx tidak jadi jalan |
Service nginx memakai depends_on ke nextjs, sehingga compose ikut menyalakan nextjs. Nilai NEXTJS_IMAGE yang berupa nama karangan akan dicoba ditarik dan gagal |
Tambahkan --no-deps pada perintah sebelum build pertama: docker compose up -d --no-deps geoserver nginx. Pesan errornya menunjuk image yang salah, bukan penyebab sebenarnya |
Terbukti saat pengujian |
Pesan The "X" variable is not set lalu kata sandi GeoServer ditolak |
Compose membaca tanda dolar pada nilai YAML sebagai awal nama variabel, bahkan di dalam tanda kutip. Karakter setelah dolar hilang tanpa error yang jelas | Jangan menulis kata sandi di docker-compose.yml. Simpan di .env dan rujuk lewat ${GEOSERVER_ADMIN_PASSWORD}. Buat dengan openssl rand -hex 16 supaya hanya berisi huruf dan angka |
Terbukti saat pengujian |
Container nextjs_portal tidak muncul walaupun docker compose ps dijalankan |
Perintah pra-build memakai --no-deps, jadi nextjs memang sengaja belum dijalankan. Container itu baru dibuat oleh Cloud Build |
Jalankan build pada bagian 17, lalu periksa docker compose ps lagi. Tiga container harus terlihat |
Terbukti saat pengujian |
| Container tidak pulih setelah start | Perlu periksa status container dan respons HTTP; penjelasan lama bahwa start tidak menjalankan proses adalah keliru | sudo docker start nginx_proxy menjalankan kembali container dan prosesnya. Periksa HTTP 200; jika gagal, periksa status dan log container |
Start berhasil pada uji Dhany 13 September 2026 |
| Alert muncul saat portal sehat dan recovered saat Nginx mati | REDUCE_COUNT_FALSE dipasangkan dengan < 1, sehingga nol kegagalan memicu alert |
Gunakan > 1, trigger count 1, alignment 60s Next older, No retest, Enabled, email open dan closure. Uji stop → incident baru → firing → start → recovered pada incident yang sama |
A yang diperbaiki terbukti: stop 11:48:02 WIB, firing sekitar 11:50, durasi incident 8 menit 42 detik, 13 September 2026 |
| Incident tetap terbuka atau masih muncul setelah condition policy diubah atau policy di-disable | Ini bug Cloud Monitoring yang diakui Google. Incident yang sedang terbuka saat condition diubah akan terus berbunyi memakai konfigurasi lama, bukan konfigurasi baru, sehingga muncul sebagai false positive di UI | Tidak ada mitigasi resmi. Incident menutup sendiri setelah 7 hari. Untuk menghindarinya: biarkan incident tertutup dulu sebelum mengubah condition, dan jangan menilai keberhasilan konfigurasi baru dari incident lama yang masih menggantung. Hapus policy tidak otomatis menutup incident yang sudah terbuka | Bug Google, terkonfirmasi di issue tracker 183505672 |
Log Nginx penuh permintaan aneh dari alamat asing, misalnya POST /device.rsp?opt=sys&cmd=___S_O_S_T_R_E_A_MAX___ |
VM dengan alamat IP publik memang dipindai otomatis, hitungan menit setelah port 80 dibuka. Permintaan seperti ini menargetkan perangkat tertentu, bukan aplikasi portal | Tidak ada yang perlu diperbaiki selama balasannya 400 atau 403. Jangan pernah menaruh berkas di luar /opt/webgis/app, dan jangan mengekspos port Docker selain 80 dan 443 |
Terlihat pada log pengujian 12 September 2026 |
Memastikan kata sandi admin GeoServer benar-benar terpakai
Section titled “Memastikan kata sandi admin GeoServer benar-benar terpakai”Jangan menilai keamanan kata sandi dari peringatan di antarmuka web. Periksa tiga hal ini, karena ketiganya berbicara langsung tentang kata sandi yang dipakai:
cd /opt/webgis/app
# 1. Kata sandi yang dilihat containersudo docker compose exec -T geoserver printenv GEOSERVER_ADMIN_PASSWORD
# 2. Format kata sandi di data directorysudo docker compose exec -T geoserver sh -c \ "grep -o 'digest1\|crypt1' /opt/geoserver/data_dir/security/usergroup/default/users.xml | head -1"
# 3. Apakah kata sandi bawaan masih diterimacurl -sS -o /dev/null -w "HTTP %{http_code}\n" \ -u "admin:geoserver" http://localhost/geoserver/rest/about/version.xmlHasil yang aman: perintah 1 menampilkan kata sandi pilihanmu, perintah 2 menampilkan
digest1, dan perintah 3 membalas 401. Kalau perintah 3 membalas 200, siapa pun yang
menemukan alamat VM dapat login dengan admin dan geoserver.
Perintah pengukuran yang dipakai untuk mengisi tabel di atas:
free -hsudo docker stats --no-streamsudo docker inspect --format '{{.Name}} OOMKilled={{.State.OOMKilled}}' geoserver_app