Aplikasi Node.js yang sudah kita jalankan sebagai service systemd sejak Bab 15, lalu kita tempatkan di balik reverse proxy app.example.local pada Bab 16, sejauh ini belum benar-benar menyimpan data apa pun. Begitu proses node di-restart atau server reboot, seluruh state yang sempat ada di memori langsung hilang tanpa bekas. Pengembang yang mengembangkan aplikasi semacam ini cepat atau lambat pasti membutuhkan tempat penyimpanan data yang persisten, terstruktur, dan dapat diandalkan meski server dinyalakan ulang berkali-kali, kebutuhan yang dijawab oleh RDBMS (Relational Database Management System).
Bab ini membuka Bagian V dengan PostgreSQL, RDBMS open source yang sering disebut komunitasnya sendiri sebagai "the world's most advanced open source database". Reputasi itu bukan sekadar slogan pemasaran; PostgreSQL dikenal luas karena kepatuhannya yang ketat terhadap standar SQL, dukungan ACID (Atomicity, Consistency, Isolation, Durability) penuh untuk menjaga integritas data, serta ekosistem extension yang sangat kaya. Kita akan mulai dari instalasi PostgreSQL 18 di Ubuntu Server 26.04, memahami dua file konfigurasi paling penting yaitu postgresql.conf dan pg_hba.conf, mempraktikkan pembuatan database beserta role dan privilege dasarnya, lalu ditutup dengan mengaktifkan koneksi remote yang aman dari luar server itu sendiri.
18.1 Instalasi PostgreSQL 18
Rilis PostgreSQL 18 pada September 2025 membawa sejumlah peningkatan signifikan di level engine, di antaranya subsistem Asynchronous I/O (AIO) yang mempercepat operasi baca dari disk, serta fungsi uuidv7() bawaan untuk menghasilkan UUID yang urut berdasarkan waktu, berguna sebagai primary key yang lebih ramah terhadap performa index dibanding UUID v4 acak. Versi inilah yang menjadi paket default PostgreSQL di repository resmi Ubuntu 26.04 LTS, sehingga instalasinya dapat memakai APT biasa tanpa perlu menambah repository pihak ketiga milik PostgreSQL Global Development Group (PGDG), konsisten dengan filosofi instalasi paket yang sudah kita jalani sejak Bab 6.
18.1.1 Arsitektur Cluster PostgreSQL di Ubuntu
Ubuntu membungkus PostgreSQL melalui paket postgresql-common, sebuah lapisan manajemen yang memungkinkan beberapa versi major PostgreSQL terpasang berdampingan di satu server tanpa saling bentrok, mirip semangat multi-versi yang sudah kita kenal dari NVM dan fnm di Bab 15 untuk Node.js. Setiap instance PostgreSQL yang berjalan di Ubuntu disebut cluster, istilah yang di sini tidak ada hubungannya dengan cluster multi-server seperti pada Kubernetes, melainkan merujuk pada satu kumpulan database yang dikelola oleh satu proses postgres yang mendengarkan di satu port tertentu. Cluster default yang dibuat setelah instalasi diberi nama main, dengan data disimpan di /var/lib/postgresql/18/main dan seluruh file konfigurasinya, termasuk postgresql.conf dan pg_hba.conf yang akan kita bahas di Bagian 18.2, ditaruh terpisah di /etc/postgresql/18/main/. Pemisahan konfigurasi dari data ini berbeda dari kebiasaan upstream PostgreSQL di distro lain yang biasanya menaruh keduanya dalam satu direktori data, serta menjadi salah satu kekhasan packaging Debian/Ubuntu yang penting diketahui Sysadmin sejak awal.
18.1.2 Instalasi Paket dan Verifikasi Service
Paket postgresql di Ubuntu adalah meta-package yang otomatis menarik versi major terbaru yang tersedia, sedangkan postgresql-contrib menambahkan sejumlah extension tambahan yang sudah teruji dan sering dipakai di lapangan, seperti pgcrypto untuk fungsi enkripsi dan pg_stat_statements untuk analisis performa query.
Langkah Praktik
- Perbarui daftar paket, lalu pasang PostgreSQL beserta paket contrib-nya.
sudo apt update sudo apt install postgresql postgresql-contrib - Instalasi otomatis membuat cluster
main, menjalankan service-nya, dan mengaktifkannya saat boot. Periksa statusnya melalui systemd.sudo systemctl status postgresql - Lihat daftar cluster PostgreSQL yang terpasang di server, termasuk versi, port, dan statusnya.
pg_lsclusters - Konfirmasi versi PostgreSQL yang benar-benar berjalan.
psql --version
Verifikasi dan Troubleshooting
- Output
pg_lsclustersyang normal menampilkan satu baris dengan versi18, nama clustermain, port5432, dan statusonline. Jika statusnyadown, jalankansudo pg_ctlcluster 18 main startuntuk menyalakannya secara manual. - Berbeda dari MySQL atau MariaDB yang akan kita bahas di Bab 19 dan 20, instalasi PostgreSQL di Ubuntu tidak pernah meminta password root database saat proses
apt installberjalan. Otentikasi awal justru diatur melalui mekanisme peer authentication yang akan kita bahas di Bagian 18.2.1. - Nomor versi minor yang tampil di
psql --versiondapat berbeda tergantung kapan repository Ubuntu terakhir disinkronkan, sama seperti catatan versi PHP di Bagian 14.1.1 dan Certbot di Bagian 17.2.2.
18.2 Konfigurasi Akses: postgresql.conf dan pg_hba.conf
PostgreSQL memisahkan pengaturan perilaku engine dari pengaturan siapa yang boleh terhubung ke dalam dua file berbeda. postgresql.conf mengatur parameter runtime seperti port yang dipakai, alamat jaringan yang didengarkan, hingga alokasi memori, sedangkan pg_hba.conf (host-based authentication) menentukan aturan siapa boleh terhubung dari mana, ke database apa, dan melalui metode otentikasi seperti apa. Memahami perbedaan dan hubungan keduanya menjadi kunci sebelum kita membuka koneksi remote di Bagian 18.4, karena kesalahan paling umum yang ditemui Sysadmin baru justru berasal dari mengira satu file saja sudah cukup diedit padahal keduanya perlu disesuaikan bersamaan.
18.2.1 Memeriksa Aturan pg_hba.conf Bawaan
Aturan di dalam pg_hba.conf dievaluasi baris demi baris dari atas ke bawah, dan PostgreSQL berhenti begitu menemukan baris pertama yang cocok dengan tipe koneksi, database, user, dan alamat asal request, lalu menerapkan metode otentikasi pada baris tersebut apa adanya. Urutan baris oleh karena itu sangat menentukan, aturan yang lebih spesifik harus ditempatkan lebih dulu dibanding aturan yang lebih umum.
Langkah Praktik
- Buka file
pg_hba.confbawaan clustermain.
Baris aktif (bukan komentar) yang relevan biasanya terlihat seperti berikut.sudo nano /etc/postgresql/18/main/pg_hba.conf# TYPE DATABASE USER ADDRESS METHOD local all postgres peer local all all peer host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 - Coba masuk ke
psqlmelalui Unix socket sebagai role sistempostgres, memakaisudo -u postgresuntuk berpindah identitas OS terlebih dahulu.sudo -u postgres psql - Ketik
\quntuk keluar, lalu coba cara kedua, terhubung melalui TCP ke alamat loopback dengan role yang sama.psql -h 127.0.0.1 -U postgres
Percobaan pertama berhasil masuk tanpa diminta password sama sekali, sedangkan percobaan kedua langsung menampilkan prompt Password for user postgres:. Inilah pg_hba.conf bekerja persis sesuai isinya: baris local ... peer cocok untuk koneksi melalui Unix socket dan memakai peer authentication, metode yang mengizinkan login tanpa password selama nama user OS di sistem sama persis dengan nama role PostgreSQL yang dituju. Baris host ... 127.0.0.1/32 ... scram-sha-256 cocok untuk koneksi TCP ke loopback dan mewajibkan password, diverifikasi melalui SCRAM-SHA-256, metode hashing password yang menjadi default PostgreSQL sejak versi 14, jauh lebih tahan terhadap serangan replay dibanding metode md5 lama yang masih sering dijumpai di tutorial usang.
Kedua metode di atas bukan satu-satunya opsi yang tersedia di kolom METHOD. Tabel berikut merangkum metode yang paling sering ditemui Sysadmin di lapangan, termasuk dua metode yang belum tampil di file bawaan ini.
| Metode | Cara Kerja | Kapan Dipakai |
|---|---|---|
peer | Mencocokkan nama user OS yang sedang login dengan nama role PostgreSQL yang dituju, tanpa password. | Koneksi lokal lewat Unix socket, terutama untuk role administratif seperti postgres. |
scram-sha-256 | Mewajibkan password, diverifikasi lewat hashing SCRAM-SHA-256 yang tahan serangan replay. | Default modern untuk koneksi TCP, baik dari loopback maupun dari jaringan, termasuk seluruh koneksi remote di Bagian 18.4. |
md5 | Mewajibkan password, diverifikasi lewat hashing MD5 yang lebih lawas dan lebih lemah dibanding SCRAM. | Kompatibilitas dengan client atau driver database lama yang belum mendukung SCRAM. |
trust | Mengizinkan koneksi tanpa verifikasi apa pun, siapa saja yang cocok dengan baris tersebut langsung diterima. | Hampir tidak pernah dipakai di server production; hanya wajar untuk container development sekali pakai yang terisolasi penuh dari jaringan luar. |
reject | Menolak koneksi secara eksplisit tanpa syarat apa pun. | Memblokir kombinasi user, database, atau alamat tertentu secara sengaja, biasanya ditempatkan di atas rule lain yang cakupannya lebih longgar. |
Verifikasi dan Troubleshooting
- Percobaan kedua di atas akan gagal dengan pesan
FATAL: password authentication failedkarena rolepostgrestidak pernah diberi password melalui instalasi APT. Kegagalan ini normal dan sengaja diperlihatkan untuk membuktikan cara kerjapg_hba.conf, bukan langkah yang perlu diperbaiki di titik ini. - Jika muncul pesan
Peer authentication failed for user "postgres"saat menjalankanpsqltanpasudo -u postgresterlebih dahulu, hal itu berarti nama user OS yang sedang login (misalnyadeploy, mengikuti user yang kita buat sejak Bab 3) tidak sama dengan nama role yang dituju, persis mekanisme peer authentication yang baru saja dijelaskan. - Perintah
\dudi dalampsqlmenampilkan daftar seluruh role yang ada di server beserta atribut masing-masing, berguna sebagai referensi cepat sepanjang bab ini.
18.3 Membuat Role, Database, dan Privilege Dasar
Skenario di bagian ini mengikuti kebutuhan Developer yang sedang menyiapkan backend baru: sebuah database bernama webapp_db untuk menyimpan data aplikasi, beserta satu role khusus bernama webapp_user yang dipakai aplikasi untuk terhubung, terpisah dari role superuser postgres yang seharusnya hanya dipegang Sysadmin. Memisahkan role aplikasi dari role administratif seperti ini adalah praktik dasar least privilege yang akan kita perdalam lagi di Bab 34, sehingga kredensial yang bocor dari sisi aplikasi tidak otomatis memberi Attacker akses penuh ke seluruh server database.
18.3.1 Membuat Role dan Database dengan Ownership yang Tepat
PostgreSQL menyebut konsep user dan group sebagai satu entitas tunggal bernama role. Sebuah role bisa login langsung layaknya user (jika diberi atribut LOGIN) atau berfungsi sebagai group yang mewadahi role lain, tanpa perlu dua sistem terpisah seperti pada beberapa RDBMS lain.
Langkah Praktik
- Masuk ke
psqlsebagai rolepostgresmelalui Unix socket, mengikuti cara yang sudah terbukti berhasil di Bagian 18.2.1.sudo -u postgres psql - Buat role baru untuk aplikasi, lengkap dengan atribut
LOGINdan password. Ganti nilai password contoh ini dengan password kuat milik sendiri sebelum dipraktikkan di server sungguhan.CREATE ROLE webapp_user WITH LOGIN PASSWORD 'S4ngatRahasia!2026'; - Buat database baru, jadikan
webapp_usersebagai owner-nya langsung saat pembuatan.CREATE DATABASE webapp_db OWNER webapp_user; - Keluar dari sesi
postgres, lalu uji login dengan role baru melalui TCP ke loopback, memanfaatkan rulescram-sha-256yang sudah ada secara default sejak Bagian 18.2.1.\q psql -h 127.0.0.1 -U webapp_user -d webapp_db
Verifikasi dan Troubleshooting
- Login yang berhasil ditandai prompt berubah menjadi
webapp_db=>. Jalankan\conninfodi dalampsqluntuk memastikan sesi benar-benar terhubung sebagaiwebapp_userke databasewebapp_db. - Pesan
FATAL: database "webapp_db" does not existbiasanya menandakan typo nama database di flag-d, sedangkanFATAL: role "webapp_user" does not existmenandakan perintahCREATE ROLEdi langkah sebelumnya belum benar-benar tereksekusi, cek kembali dengan\du.
18.3.2 Memahami Privilege Dasar dan Perubahan Schema Public sejak PostgreSQL 15
Sebelum PostgreSQL 15, schema public di setiap database baru secara default memberi privilege CREATE kepada seluruh role melalui role semu bernama PUBLIC, artinya siapa pun yang berhasil login ke database tersebut, bahkan melalui role dengan privilege minim, bisa membuat table sembarangan di schema itu. Perilaku ini dianggap terlalu longgar dari sisi keamanan, sehingga sejak PostgreSQL 15 privilege CREATE pada schema public tidak lagi otomatis diberikan ke PUBLIC. Sebagai gantinya, database baru memiliki schema public yang dimiliki role semu pg_database_owner, yang secara otomatis mewakili siapa pun yang menjadi owner database tersebut. Karena langkah 18.3.1 di atas sudah membuat webapp_db dengan OWNER webapp_user sejak awal, webapp_user otomatis mewarisi hak penuh atas schema public di database itu tanpa perlu perintah GRANT tambahan apa pun, pola yang menjadi cara paling bersih untuk menghindari kerumitan privilege schema di PostgreSQL versi modern.
Buktikan langsung dengan mencoba membuat table sederhana memakai sesi webapp_user yang masih terbuka dari langkah sebelumnya.
CREATE TABLE notes (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
INSERT INTO notes (content) VALUES ('Database webapp_db siap dipakai');
SELECT * FROM notes;Ketiga perintah di atas harus berjalan mulus tanpa satu pun pesan permission denied. Untuk kebutuhan yang lebih kompleks, misalnya role tambahan yang hanya boleh membaca data tanpa bisa mengubahnya, seperti akun yang dipakai tool reporting atau dashboard BI, privilege granular bisa diberikan langsung ke table tertentu tanpa menyentuh ownership database sama sekali.
CREATE ROLE webapp_readonly WITH LOGIN PASSWORD 'B4caSaja!2026';
GRANT CONNECT ON DATABASE webapp_db TO webapp_readonly;
GRANT USAGE ON SCHEMA public TO webapp_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO webapp_readonly;Tiga baris GRANT ini masing-masing mewakili lapisan privilege berbeda: CONNECT mengizinkan role sekadar membuka koneksi ke database, USAGE pada schema mengizinkan role "melihat ke dalam" schema public (tanpa itu pun sudah cukup untuk memblokir akses meski privilege table sudah diberikan), dan SELECT pada table baru benar-benar mengizinkan pembacaan data. Ketiganya harus ada bersamaan, hilang salah satu saja koneksi tetap akan ditolak atau query akan gagal dengan permission denied.
Verifikasi dan Troubleshooting
- Perintah
\dp notesdi dalampsqlmenampilkan tabel access privileges untuk tablenotes, cara cepat mengaudit siapa punya privilege apa tanpa perlu membaca ulang seluruh riwayat perintahGRANT. - Privilege
GRANT ... ON ALL TABLES IN SCHEMA publichanya berlaku untuk table yang sudah ada saat perintah dijalankan. Table baru yang dibuat setelahnya tidak otomatis ikut ter-cover, kecuali dikombinasikan denganALTER DEFAULT PRIVILEGES, topik lanjutan yang baik untuk digali lebih jauh saat aplikasi produksi mulai punya banyak table.
18.4 Koneksi Remote yang Aman
Sejauh ini seluruh koneksi yang kita uji coba berasal dari server itu sendiri, baik melalui Unix socket maupun melalui alamat loopback 127.0.0.1. Di dunia nyata, database sering diakses dari mesin lain, misalnya laptop Developer yang sedang menulis kode aplikasi, atau server aplikasi terpisah yang memanggil database melalui jaringan internal. Membuka akses semacam ini butuh tiga perubahan sekaligus: PostgreSQL harus mau mendengarkan di interface jaringan (bukan cuma loopback), pg_hba.conf harus punya rule untuk alamat asal yang dimaksud, dan firewall di level OS harus mengizinkan traffic ke port database.
18.4.1 Mengaktifkan listen_addresses dan Menambah Rule pg_hba.conf
Langkah Praktik
- Buka
postgresql.conf, cari directivelisten_addressesyang secara default bernilailocalhost.
Ubah baris tersebut agar PostgreSQL mendengarkan di seluruh interface jaringan yang dimiliki server.sudo nano /etc/postgresql/18/main/postgresql.conflisten_addresses = '*' - Directive
listen_addressestergolong parameter yang hanya dibaca saat proses PostgreSQL pertama kali start, berbeda dari rulepg_hba.confyang cukup di-reload. Restart penuh cluster-nya agar perubahan ini benar-benar terpakai.sudo systemctl restart postgresql - Tambahkan rule baru di
pg_hba.conf, mengizinkan koneksi dari seluruh network lab192.168.1.0/24yang sudah kita pakai konsisten sejak Bab 8, khusus ke databasewebapp_dbdengan rolewebapp_usersaja, bukan mengizinkan seluruh role ke seluruh database.sudo nano /etc/postgresql/18/main/pg_hba.conf
Tempatkan baris ini sebelum barishost webapp_db webapp_user 192.168.1.0/24 scram-sha-256host all all ...yang sudah ada jika rule tersebut turut mencakup network yang sama, mengikuti prinsip evaluasi top-down yang sudah dibahas di Bagian 18.2.1. - Rule
pg_hba.confcukup di-reload tanpa restart penuh, sehingga koneksi yang sedang berjalan tidak terputus.sudo systemctl reload postgresql
Verifikasi dan Troubleshooting
- Pastikan PostgreSQL benar-benar mendengarkan di semua interface, bukan cuma loopback.
Output yang benar menampilkan alamatss -tlnp | grep 54320.0.0.0:5432, bukan127.0.0.1:5432. - Membuka
listen_addresseske*lalu mengizinkan rulepg_hba.confdengan cakupan network sesempit mungkin, seperti192.168.1.0/24alih-alih0.0.0.0/0, adalah kombinasi yang jauh lebih aman dibanding mengekspos database ke seluruh internet. Database production hampir tidak pernah punya alasan menerima koneksi langsung dari internet publik, kesalahan konfigurasi yang berulang kali jadi penyebab kebocoran data di berbagai insiden nyata.
18.4.2 Membuka Firewall UFW untuk Port PostgreSQL
PostgreSQL default berjalan di port 5432. Sama seperti port 443 yang baru kita buka khusus untuk kebutuhan HTTPS di Bagian 17.3.2, port database ini juga perlu dibuka secara eksplisit di UFW, dibatasi hanya untuk sumber dari network lab, bukan dibuka bebas untuk semua orang.
Langkah Praktik
- Tambahkan rule UFW yang mengizinkan traffic ke port 5432 khusus dari network
192.168.1.0/24.sudo ufw allow from 192.168.1.0/24 to any port 5432 proto tcp - Pastikan rule tersebut benar-benar tercatat.
sudo ufw status
Verifikasi dan Troubleshooting
- Output
ufw statusharus menampilkan baris5432/tcpdengan actionALLOWdan sumber192.168.1.0/24, bukanAnywhere. - Jika UFW belum aktif sama sekali di server ini, aktifkan dulu dengan
sudo ufw enable, tetapi pastikan rule SSH dari Bab 3 sudah ada lebih dulu supaya sesi remote yang sedang berjalan tidak ikut terputus.
18.4.3 Menguji Koneksi dari Client Lain di Jaringan
Langkah Praktik
- Dari komputer lain di jaringan lab yang sama, misalnya laptop Developer, pasang PostgreSQL client saja tanpa server penuhnya.
sudo apt install postgresql-client - Coba terhubung ke server database melalui IP
192.168.1.20, memakai role dan database yang sudah dibuat di Bagian 18.3.1.psql -h 192.168.1.20 -U webapp_user -d webapp_db
Verifikasi dan Troubleshooting
- Koneksi yang berhasil akan meminta password lalu menampilkan prompt
webapp_db=>, identik dengan pengujian melalui loopback di Bagian 18.3.1, hanya kali ini benar-benar melewati jaringan. - Pesan
psql: error: connection to server ... failed: Connection refusedmenandakan PostgreSQL belum mendengarkan di interface jaringan atau firewall masih memblokir port 5432, kembali periksa Bagian 18.4.1 dan 18.4.2. - Pesan
FATAL: no pg_hba.conf entry for host "192.168.1.x", user "webapp_user", database "webapp_db"menandakan rule dipg_hba.confbelum cocok, entah karena subnet yang dituliskan salah atau baris tersebut tertimpa baris lain yang posisinya lebih atas. - Percobaan role
webapp_readonlydari Bagian 18.3.2 ke databasewebapp_dbmelalui jaringan akan gagal dengan pesanpg_hba.confyang sama, karena rule di Bagian 18.4.1 sengaja hanya mencakupwebapp_user. Menambah role lain ke akses remote berarti menambah barispg_hba.confbaru secara sadar, bukan melebarkan rule yang sudah ada begitu saja. - Koneksi melalui jaringan lab internal seperti ini masih berupa traffic TCP polos tanpa enkripsi, cukup aman selama network-nya benar-benar tepercaya. Untuk database yang diakses melalui jaringan yang lebih terbuka atau lintas data center, PostgreSQL mendukung koneksi TLS melalui directive
ssl = onbeserta pasangan sertifikat dan private key, memakai prinsip yang persis sama dengan TLS di Nginx dan Apache yang sudah kita bahas mendalam di Bab 17.
Sampai di sini, server sudah menjalankan PostgreSQL 18 lengkap dengan database webapp_db yang dimiliki role aplikasi tersendiri, terpisah dari role administratif postgres, dan bisa diakses dengan aman dari jaringan lab melalui rule pg_hba.conf serta firewall yang dibatasi ketat. Bab 19 melanjutkan Bagian V dengan RDBMS kedua, MySQL, membandingkan langsung cara kerjanya dengan PostgreSQL termasuk perbedaan filosofi otentikasi dan manajemen privilege antara keduanya.

