SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-08-07

SQLite di VPS: Tepat untuk Produksi atau Tidak?

Pelajari kapan SQLite cocok untuk produksi di satu VPS, cara memakai WAL dan busy_timeout, replikasi Litestream, serta batas satu penulis dan satu mesin.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Kapan SQLite menjadi database produksi yang tepat pada VPS

Menjalankan SQLite di lingkungan produksi pada VPS merupakan pilihan yang tepat untuk sebagian besar aplikasi kecil. Alasannya sederhana: satu proses pada satu mesin yang menulis ke satu file tidak memerlukan server database. Tidak ada daemon yang perlu diawasi, tidak ada port yang perlu diatur firewall-nya, tidak ada password yang perlu dirotasi, dan tidak ada mesin kedua yang harus tetap aktif. Query merupakan pemanggilan fungsi, bukan perjalanan pulang-pergi melalui jaringan. Karena itu, halaman yang menjalankan empat puluh query memerlukan empat puluh pemanggilan fungsi.

Batasannya sempit, tetapi nyata. SQLite hanya mengizinkan satu penulis pada satu waktu di seluruh file database, dan file tersebut tidak dapat digunakan bersama oleh dua mesin. Kedua batasan ini tidak menjadi masalah untuk satu VPS yang menjalankan satu aplikasi. Namun, keduanya menjadi penghambat serius segera setelah kebutuhan Anda melampaui pola tersebut. Panduan ini membahas pengaturan yang membuat SQLite aman di server, pencadangan berkelanjutan dengan Litestream, serta kondisi ketika Anda harus berhenti menggunakannya.

Instal alat command line terlebih dahulu. Semua perintah di bawah ini dijalankan pada Ubuntu 24.04.

sudo apt update
sudo apt install -y sqlite3
sqlite3 --version

Perintah tersebut menampilkan versi yang diawali dengan 3., kemudian tanggal build dan hash sumber. Ubuntu 24.04 menyediakan SQLite 3.45.1 pada Juli 2026. Aplikasi Anda kemungkinan tidak menggunakan binary ini. Sebagian besar runtime bahasa pemrograman menyertakan salinan library SQLite sendiri, yang sering kali lebih baru. Karena itu, periksa versi yang dilaporkan oleh database driver Anda sebelum mengandalkan fitur terbaru.

Mengapa mode WAL menjadi perubahan pertama yang perlu dilakukan

Secara default, SQLite menggunakan rollback journal. Sebelum mengubah sebuah halaman, SQLite menyalin halaman asli ke file -journal, lalu mengedit database secara langsung. Agar proses ini aman, SQLite mengambil exclusive lock pada seluruh file. Akibatnya, semua pembaca harus menunggu selama ada proses penulisan. Pada laptop, hal ini biasanya tidak terlihat. Pada web server, satu proses penulisan yang lambat dapat menunda setiap request yang mengakses database.

Mode WAL (write-ahead log) membalik urutan tersebut. Writer menambahkan halaman baru ke file -wal terpisah dan membiarkan database utama tetap utuh. Reader tetap membaca file utama berdasarkan snapshot saat pembacaan dimulai. Dengan demikian, reader tidak memblokir writer, dan writer tidak memblokir reader. Selanjutnya, checkpoint menyalin halaman WAL yang telah terkumpul kembali ke database utama. Perubahan tunggal ini merupakan faktor utama yang membuat SQLite dapat digunakan di balik aplikasi web.

Aktifkan mode WAL dan pastikan mode tersebut tetap aktif

mkdir -p ~/app
sqlite3 ~/app/app.db "PRAGMA journal_mode=WAL;"

Perintah tersebut mencetak wal. Output itu bukan sekadar hiasan. PRAGMA journal_mode mengembalikan mode yang benar-benar digunakan database, sehingga respons delete berarti perubahan gagal dan database masih menggunakan rollback journal.

Mode WAL bersifat persisten. Mode ini disimpan sebagai flag pada header database, bukan sebagai pengaturan koneksi. Karena itu, Anda cukup menjalankannya sekali untuk setiap file database. Semua koneksi berikutnya akan mewarisi mode tersebut, termasuk setelah reboot. Buktikan dengan koneksi baru.

sqlite3 ~/app/app.db "PRAGMA journal_mode;"

Sekarang buat sebuah tabel dan periksa file yang muncul di disk.

sqlite3 ~/app/app.db <<'SQL'
CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT NOT NULL);
INSERT INTO notes (body) VALUES ('first row');
SQL
ls -l ~/app/

Sekarang ada tiga file: app.db, app.db-wal, dan app.db-shm. File -wal berisi halaman yang sudah di-commit tetapi belum menjalani checkpoint. File -shm adalah indeks shared memory yang dipetakan oleh setiap koneksi agar semuanya mengetahui isi WAL. Keduanya merupakan bagian dari database, bukan file sementara. Jika Anda hanya menyalin app.db saat aplikasi masih berjalan, Anda akan mendapatkan file yang tidak berisi commit terbaru. Jika Anda menghapus app.db dan membiarkan dua file lainnya tetap ada, SQLite akan menerapkan halaman WAL yang sudah usang tersebut ke file baru apa pun yang muncul dengan nama itu. Inilah cara database baru dapat rusak saat seseorang mencoba mereset database.

Pengaturan koneksi yang dibutuhkan setiap aplikasi produksi

Hanya journal_mode yang disimpan dalam database. Semua pengaturan lain di bawah ini berlaku per koneksi. Artinya, aplikasi Anda harus menjalankannya pada setiap koneksi yang dibuka, termasuk setiap koneksi yang dibuat pool di latar belakang.

PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;

busy_timeout = 5000 memberi tahu SQLite untuk terus mencoba kembali selama maksimal 5000 milidetik saat database terkunci sebelum mengembalikan database is locked. Nilai default-nya adalah 0. Artinya, secara default, SQLite langsung gagal saat dua operasi tulis pertama kali berjalan bersamaan. Menetapkan satu nilai ini menghilangkan sebagian besar error penguncian yang sering dianggap sebagai masalah SQLite itu sendiri.

synchronous = NORMAL adalah pengaturan yang tepat dalam mode WAL, dan konsekuensinya perlu dipahami. Pada FULL, SQLite memanggil fsync pada WAL setiap kali commit. Pada NORMAL, SQLite melakukan sinkronisasi saat checkpoint. Dokumentasi SQLite menjelaskan dengan tegas hal yang dikorbankan: transaksi tidak lagi tahan terhadap kegagalan daya atau hard reset. Database tidak akan rusak akibat kehilangan daya tersebut. Anda hanya kehilangan commit terakhir yang belum tersimpan ke disk. Pada VPS, ini biasanya merupakan kompromi yang tepat karena fsync dihapus dari jalur setiap operasi tulis.

foreign_keys = ON dinonaktifkan secara default demi kompatibilitas dengan versi sebelumnya, dan pengaturan ini berlaku per koneksi. Skema yang penuh dengan klausa REFERENCES sama sekali tidak menegakkan aturan sampai setiap koneksi mengaktifkan pengaturan ini.

Ada satu pengaturan lain yang baru penting pada tahap berikutnya. SQLite secara otomatis menjalankan checkpoint setelah WAL berukuran lebih dari 1000 halaman. Proses tersebut dijalankan oleh koneksi mana pun yang kebetulan menyelesaikan transaksi pada saat itu. Hal ini tidak bermasalah dengan sendirinya. Namun, situasinya perlu dipertimbangkan saat Litestream berjalan karena Litestream ingin mengendalikan waktu pelaksanaan checkpoint.

Mengapa database is locked masih terjadi setelah Anda menetapkan busy_timeout

Inilah kegagalan yang membuat orang kembali menggunakan Postgres, dan penyebabnya spesifik.

Batas waktu busy memasang busy handler, tetapi SQLite tidak menjamin akan memanggilnya.

Jika SQLite menentukan bahwa pemanggilan busy handler dapat menyebabkan deadlock, SQLite akan langsung mengembalikan SQLITE_BUSY ke aplikasi, bukan memanggil busy handler.

Deadlock yang dihindari terjadi saat transaksi mengalami peningkatan level. BEGIN tanpa klausa tambahan di SQLite berarti BEGIN DEFERRED. Jika pernyataan pertama setelahnya adalah SELECT, Anda berada dalam transaksi baca. Saat UPDATE berikutnya dalam transaksi yang sama perlu berubah menjadi transaksi tulis, dan koneksi lain telah melakukan penulisan sejak pembacaan Anda dimulai, SQLite tidak dapat membuat Anda menunggu. Snapshot Anda sudah kedaluwarsa, dan menunggu hanya akan menyebabkan kedua koneksi saling menunggu hingga deadlock. Dokumentasi menyatakan hasilnya secara langsung:

Pernyataan tulis berikutnya akan meningkatkan transaksi menjadi transaksi tulis jika memungkinkan, atau mengembalikan SQLITE_BUSY.

Batas waktu 5000 milidetik Anda tidak pernah digunakan. Error langsung muncul, sehingga tampak seolah-olah pengaturan tersebut tidak berpengaruh.

Perbaikannya hanya memerlukan satu kata.

BEGIN IMMEDIATE;
UPDATE notes SET body = 'edited' WHERE id = 1;
COMMIT;

BEGIN IMMEDIATE mengambil write lock pada awal transaksi, sebelum membaca apa pun. Tidak ada peningkatan level, sehingga tidak ada deadlock yang perlu dihindari. Karena itu, busy handler akan diterapkan dan koneksi menunggu gilirannya, bukan gagal. Biarkan transaksi hanya-baca tetap menggunakan mode deferred. Setiap transaksi yang berisi penulisan harus menggunakan mode immediate.

Penyebab kedua error lock lebih sulit ditemukan: membiarkan transaksi tulis tetap terbuka selama pekerjaan yang lambat. SQLite membuat penulis berjalan secara serial, sehingga transaksi yang dibuka, memanggil API eksternal melalui jaringan, lalu melakukan commit akan memblokir setiap penulis lain selama pemanggilan tersebut berlangsung. Baca data yang diperlukan, tutup transaksi, lakukan pekerjaan yang lambat, lalu buka transaksi tulis singkat untuk menyimpan hasilnya.

Pencadangan berkelanjutan dengan Litestream

Salinan malam hari dapat kehilangan hingga satu hari perubahan, dan menjalankan cp pada database SQLite yang sedang digunakan dapat menghasilkan salinan yang tidak dapat dibuka. Ada dua cara yang aman. sqlite3 app.db ".backup /path/to/backup.db" menggunakan antarmuka pencadangan online SQLite dan dapat bekerja pada database yang sedang digunakan. Litestream melangkah lebih jauh: Litestream memantau WAL dan terus-menerus mengirim perubahan ke object storage. Dengan demikian, potensi kehilangan data terburuk berkurang dari satu hari menjadi sekitar satu detik.

Litestream adalah satu binary Go yang berjalan di samping aplikasi. Litestream tidak berada di antara aplikasi dan database. Aplikasi Anda tetap menulis ke SQLite seperti biasa, sedangkan Litestream membaca WAL dan mengunggah perubahan.

cd /tmp
curl -fsSL -O https://github.com/benbjohnson/litestream/releases/download/v0.5.14/litestream-0.5.14-linux-x86_64.deb
sudo dpkg -i litestream-0.5.14-linux-x86_64.deb
litestream version

v0.5.14 adalah rilis yang didokumentasikan pada halaman instalasi Linux resmi per July 2026, dan v0.5.15 dirilis pada 21 July 2026. Ubah versi pada kedua baris agar sesuai dengan tag saat ini pada halaman releases. Gunakan paket arm64 yang sesuai jika VPS Anda menggunakan arm64.

File konfigurasi berada di /etc/litestream.yml. Mulailah dengan replica file lokal karena cara ini membuktikan seluruh alur tanpa memerlukan kredensial cloud.

dbs:
  - path: /home/appuser/app/app.db
    replica:
      type: file
      path: /var/backups/litestream/app

Perhatikan bahwa field tersebut adalah replica, dalam bentuk tunggal. Litestream 0.5 mengganti array replicas dari seri 0.3 dengan satu blok replica. Konfigurasi yang berisi dua entri sekarang gagal saat startup. Banyak panduan pihak ketiga masih menampilkan array lama. Karena itu, salin struktur di atas, bukan contoh pertama yang muncul dalam hasil pencarian. Seri 0.5 juga mengganti nama subcommand litestream wal menjadi litestream ltx karena format backup pada disk berubah.

Periksa bahwa konfigurasi dapat di-parse sebelum mengaktifkan apa pun.

sudo litestream databases -config /etc/litestream.yml

Selanjutnya, buktikan alur pulang-pergi secara manual. Bentuk ini melewati file konfigurasi dan mereplikasi satu database ke satu path.

mkdir -p /tmp/replica
litestream replicate ~/app/app.db file:///tmp/replica/app

Perintah tersebut berjalan di foreground dan tetap aktif. Pada shell kedua, tulis satu row lalu restore replica ke file baru.

sqlite3 ~/app/app.db "INSERT INTO notes (body) VALUES ('written after replication started');"
litestream restore -o /tmp/restored.db file:///tmp/replica/app
sqlite3 /tmp/restored.db "SELECT count(*) FROM notes;"

Jumlah tersebut mencakup row baru. Jika tidak, perubahan belum tersinkronisasi: Litestream melakukan push pada sync-interval yang secara default bernilai 1 second. Tunggu, lalu lakukan restore lagi. Satu detik tersebut juga merupakan recovery point Anda. Jika terjadi crash, paling banyak perubahan dari interval sinkronisasi terakhir yang hilang. Tidak ada konfigurasi yang dapat membuat kehilangan tersebut menjadi nol.

Untuk storage produksi, ganti blok replica dengan URL S3. Cara ini dapat digunakan dengan Amazon S3 dan object storage yang kompatibel dengan S3 dari provider lain.

dbs:
  - path: /home/appuser/app/app.db
    replica:
      url: s3://your-bucket-name/app
      region: us-east-1

snapshot:
  interval: 24h
  retention: 24h

Jangan menyimpan kredensial di file tersebut. Litestream membaca LITESTREAM_ACCESS_KEY_ID dan LITESTREAM_SECRET_ACCESS_KEY dari environment. Karena itu, simpan keduanya dalam systemd drop-in yang dimiliki oleh root dengan mode 600.

Nilai snapshot di atas adalah nilai default, dan default retention sering mengejutkan pengguna. Retention menentukan berapa lama Litestream menyimpan snapshot serta file yang terkait dengannya. Jadi, retention juga menentukan seberapa jauh ke masa lalu Anda dapat melakukan restore. Retention selama dua puluh empat jam berarti migrasi bermasalah yang baru diketahui pada Rabu pagi sudah tidak dapat dipulihkan dari state hari Senin. Atur retention: 168h selama satu minggu dan tanggung biaya storage tambahan.

Buktikan pemulihan sebelum Anda membutuhkannya

litestream restore -o /tmp/check.db /home/appuser/app/app.db
sqlite3 /tmp/check.db "PRAGMA integrity_check;"
sqlite3 /tmp/check.db "SELECT count(*) FROM notes;"

Dengan path database, litestream restore mencari replika yang sesuai di /etc/litestream.yml lalu mengunduhnya. PRAGMA integrity_check menampilkan ok pada file yang sehat. Output lainnya berarti salinan hasil pemulihan tidak dapat digunakan. Jalankan proses ini secara terjadwal dengan service dan timer systemd, lalu baca outputnya. Sebelum Anda memulihkan backup setidaknya sekali, Anda belum tahu apakah proses tersebut berfungsi.

Jalankan Litestream dengan systemd

Paket Debian memasang unit litestream yang membaca /etc/litestream.yml.

sudo systemctl enable litestream
sudo systemctl start litestream
sudo journalctl -u litestream -f

Output yang sehat menampilkan setiap database dari konfigurasi, lalu tidak menampilkan apa pun selain baris sinkronisasi berkala. Error no such file or directory pada path database berarti path dalam konfigurasi salah atau proses tidak dapat membacanya. Secara default, unit berjalan sebagai root. Hak akses ini lebih besar daripada yang diperlukan tugas tersebut. Litestream harus dapat membaca dan menulis database serta direktori tempat database berada karena Litestream menggunakan file -wal dan -shm yang berada di samping database. Karena itu, gunakan akun yang sudah dipakai aplikasi Anda.

# /etc/systemd/system/litestream.service.d/override.conf
[Service]
User=appuser
Group=appuser

Terapkan perubahan tersebut dengan sudo systemctl daemon-reload dan sudo systemctl restart litestream. Menyiapkan akun service khusus dengan hak akses minimum hanya memerlukan beberapa menit. Langkah ini membedakan agen pencadangan dari proses root kedua pada server.

Satu detail urutan penting jika Anda membangun ulang mesin dari awal. Database harus dipulihkan sebelum aplikasi dijalankan. litestream restore menerima -if-db-not-exists, yang mengembalikan kode keluar 0 jika file sudah ada. Karena itu, perintah ini aman dijalankan pada setiap boot. Tambahkan perintah tersebut sebagai baris ExecStartPre pada unit aplikasi. Dengan begitu, VPS baru akan mengunduh database, sedangkan VPS yang sudah memiliki database tidak melakukan apa pun. litestream replicate memiliki flag -restore-if-db-not-exists yang setara jika Anda ingin menyimpannya di satu tempat.

Batas SQLite pada VPS

Sistem file jaringan. Ini adalah batasan yang tidak dapat diatasi dengan konfigurasi. Mode WAL mengharuskan setiap proses yang menggunakan database berbagi area kecil di memori. Area tersebut disediakan oleh file -shm. Dokumentasi SQLite menyatakan aturan ini tanpa pengecualian:

Semua proses yang menggunakan database harus berada pada komputer host yang sama; WAL tidak berfungsi melalui sistem file jaringan.

Database pada NFS ter-mount (network file system) atau share SMB dapat rusak, dan tidak ada pragma yang dapat mencegahnya. Ada perbedaan yang sering terlewatkan. Perangkat block jaringan, yang digunakan sebagian besar penyedia VPS sebagai penyimpanan tambahan, terlihat oleh Linux sebagai disk biasa dengan sistem file biasa. Konfigurasi tersebut aman. Sebaliknya, file share yang di-mount tidak aman.

Server aplikasi kedua. Tidak ada pengaturan yang dapat membuat konfigurasi ini berfungsi. Jika dua mesin perlu menyajikan data yang sama, Anda memerlukan database yang berkomunikasi melalui jaringan. Rencanakan perpindahan tersebut selagi masih ada waktu untuk mempersiapkannya.

Beban kerja dengan banyak operasi tulis. Satu penulis pada satu waktu merupakan karakteristik format file, bukan pengaturan yang dapat disesuaikan. Operasi tulis singkat tidak mahal karena setiap commit ditambahkan ke WAL. Karena itu, throughput lebih dipengaruhi latensi penulisan kecil pada disk daripada CPU. Lihat NVMe dibandingkan penyimpanan SATA SSD pada VPS untuk melihat perbedaan tersebut. Masalah sebenarnya adalah transaksi yang berlangsung lama karena transaksi itu membuat semua penulis lain mengantre di belakangnya.

Kueri analitis. SQLite adalah row store yang dibuat untuk transaksi. Dashboard yang memindai seratus juta baris merupakan pekerjaan berbeda yang memerlukan alat berbeda. DuckDB dibandingkan dengan SQLite untuk pekerjaan server menjelaskan batas penggunaannya.

VACUUM dalam replikasi. VACUUM penuh menulis ulang seluruh file database. Litestream harus mengunggah seluruh file tersebut lagi, dan dokumentasi Litestream menyarankan agar operasi ini tidak dijalankan saat replikasi aktif. Hentikan replicator, jalankan vacuum, lalu jalankan kembali replicator. Siapkan diri untuk snapshot penuh yang baru.

Dua replicator pada satu database. Jangan pernah menjalankan dua proses Litestream pada database yang sama atau tujuan replica yang sama. Dokumentasi menyatakan dengan jelas bahwa Anda bertanggung jawab untuk mencegah kondisi ini. Jika terjadi, replica tidak dapat dipulihkan.

Hal yang tidak ditangani Litestream

Litestream melindungi file database dan tidak menangani hal lain. File yang diunggah, konfigurasi aplikasi, sertifikat TLS (transport layer security), dan file unit tetap harus Anda tangani sendiri. Gunakan bersama backup terenkripsi di luar server menggunakan restic secara terjadwal agar kedua bagian tersebut terlindungi. Jika mesin masih baru, sepuluh menit pertama pada VPS baru membahas konfigurasi akun pengguna dan firewall yang diasumsikan sudah selesai dalam panduan ini.

FAQ

Apakah SQLite cukup untuk aplikasi produksi?

Untuk satu aplikasi pada satu server, ya, asalkan Anda mengaktifkan mode WAL, menetapkan batas waktu busy, dan mencadangkannya secara berkelanjutan. Batasan yang penting bersifat struktural: hanya ada satu writer pada satu waktu dan hanya satu mesin host. Aplikasi yang masih berada dalam batas tersebut memperoleh database tanpa lompatan jaringan dan tanpa proses terpisah yang harus dipantau. Aplikasi yang melampaui batas tersebut memerlukan database client-server, dan tuning apa pun tidak akan mengubahnya.

Mengapa saya masih mendapatkan database is locked setelah menetapkan busy_timeout?

Karena SQLite melewati busy handler ketika penantian dapat menyebabkan deadlock. Transaksi yang dimulai dengan BEGIN tanpa klausa lain bersifat deferred: SELECT pembuka menempatkannya dalam transaksi baca, lalu penulisan berikutnya harus meningkatkan tingkat transaksi. Jika koneksi lain melakukan penulisan di antaranya, SQLite segera mengembalikan SQLITE_BUSY, bukan memanggil busy handler Anda, karena snapshot baca Anda sudah kedaluwarsa. Mulai setiap transaksi yang akan melakukan penulisan dengan BEGIN IMMEDIATE agar write lock diambil sejak awal dan batas waktu berlaku.

Dapatkah saya menyimpan database SQLite pada penyimpanan jaringan?

Tidak pada filesystem jaringan seperti NFS atau SMB. Mode WAL memerlukan semua proses untuk berbagi memori melalui file -shm, dan dokumentasi SQLite menyatakan bahwa setiap proses yang menggunakan database harus berada pada komputer host yang sama. Network block device yang dipasang oleh provider Anda merupakan hal yang berbeda: Linux melihatnya sebagai disk biasa dengan filesystem biasa, dan SQLite dapat bekerja di sana.

Apakah saya memerlukan Litestream jika sudah menjalankan pencadangan setiap malam?

Hal ini bergantung pada seberapa banyak data yang dapat Anda tanggung untuk hilang. Pekerjaan pencadangan setiap malam berarti Anda dapat kehilangan penulisan hingga dua puluh empat jam terakhir. Litestream melakukan sinkronisasi sekitar sekali per detik, sehingga kerusakan hanya menyebabkan hilangnya data sekitar satu detik terakhir. Litestream juga lebih aman daripada menyalin file database dengan cp, yang dapat menangkap database saat penulisan sedang berlangsung. Litestream hanya mencakup database, jadi tetap jalankan pencadangan file umum secara berdampingan.

#sqlite#wal#litestream#backups#production