Halo Sobat Online! Menitipkan foto, dokumen kerja, dan arsip pribadi ke layanan cloud orang lain itu mirip menaruh berkas penting di rumah kos: praktis, tapi kuncinya bukan milik kita. Di artikel ini kita akan self-host Nextcloud di VPS memakai Docker Compose — satu file, empat kontainer, dan kamu punya cloud pribadi sendiri tanpa biaya bulanan.
Setelah selesai, kamu bisa menyinkronkan file dari HP dan laptop, menyimpan kalender serta kontak, sampai membagikan folder lewat tautan — semuanya dari server yang kamu pegang kuncinya.
Kenapa Self-Host Nextcloud di VPS Layak Dicoba?
Aplikasi ini sudah dipakai jutaan orang sebagai pengganti Google Drive atau Dropbox, dan alasan memindahkannya ke server sendiri cukup masuk akal:
- Kapasitas ditentukan disk servermu, bukan paket langganan. VPS 40 GB berarti ruang 40 GB, bukan 15 GB gratis lalu disuruh upgrade.
- File tidak dipindai iklan. Tidak ada analisis isi dokumen untuk menawarkan barang.
- Backup utuh bisa kamu kopi sendiri. Database, konfigurasi, dan file ada di dua volume Docker yang gampang diarsipkan.
- Open-source dan gratis. Tidak ada batas jumlah pengguna atau perangkat.
Anggap saja Nextcloud ini lemari arsip di rumah sendiri: kamu yang pegang kuncinya, dan kamu yang tahu siapa saja boleh masuk.
Bedanya dengan Gitea, Umami, dan Vaultwarden
Kita sudah pernah membahas Gitea untuk kode, Umami untuk analitik, dan Vaultwarden untuk password. Nextcloud melengkapi perabot cloud pribadimu di sisi paling dasar: file, kalender, kontak, catatan, dan berbagi tautan. Kalau Vaultwarden menyimpan kunci, Nextcloud menyimpan isi lemari.
Apa Saja yang Perlu Disiapkan
Bereskan lima hal ini dulu supaya tidak tersandung di tengah jalan:
- VPS Ubuntu 22.04 atau 24.04 dengan akses root lewat SSH. RAM 2 GB sudah nyaman; 1 GB masih bisa jalan tapi sempit saat sinkronisasi pertama.
- Docker Engine dan plugin Docker Compose. Pastikan dengan
docker compose version. - Ruang disk minimal 20 GB — seluruh file pengguna tinggal di sini, bukan di database.
- Domain khusus, misalnya
cloud.domainmu.com, sudah diarahkan ke IP VPS lewat record A. - Tiga password kuat: root MariaDB, user database Nextcloud, dan Redis. Siapkan sebelum instalasi karena kita isi lewat variabel lingkungan.
Satu catatan versi yang penting supaya artikel ini tidak menuntunmu ke jalur usang. Saat tulisan ini disusun, jalur produksi yang kita pakai adalah Nextcloud 34 (Hub 26 Spring) yang didukung sampai Juni 2027. Nextcloud 35 (Hub 26 Summer) sudah dirilis 16 September 2026, tetapi kita sengaja memakukan tag per major (34-apache) karena Nextcloud menolak lompat dua major sekaligus. Tag latest atau apache mengikuti versi terbaru tanpa bertanya, jadi jangan dipakai untuk server produksi.
Langkah 1: Siapkan Folder Proyek dan File .env
Masuk sebagai root, lalu buat satu folder rapi di /opt/nextcloud:
mkdir -p /opt/nextcloud
cd /opt/nextcloud
Sekarang buat file .env berisi semua rahasia. Buat seperti ini, lalu ganti setiap nilainya dengan passwordmu sendiri:
MYSQL_ROOT_PASSWORD=ubah-ini-root
MYSQL_PASSWORD=ubah-ini-nextcloud
REDIS_PASSWORD=ubah-ini-redis
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=ubah-ini-admin
NEXTCLOUD_DOMAIN=cloud.domainmu.com
Kenapa dipisah dari compose? Supaya password tidak menempel di file yang sering kamu bagikan atau tempel ke forum saat minta bantuan. Pastikan juga izin filenya ketat: chmod 600 .env.
Langkah 2: Rakit docker-compose.yml
Ini inti artikelnya. Empat kontainer, satu file, simpan sebagai /opt/nextcloud/docker-compose.yml:
name: nextcloud
services:
db:
image: mariadb:11.4
restart: unless-stopped
command:
- --transaction-isolation=READ-COMMITTED
- --log-bin=binlog
- --binlog-format=ROW
environment:
MARIADB_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MARIADB_DATABASE: nextcloud
MARIADB_USER: nextcloud
MARIADB_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 20s
timeout: 5s
retries: 10
redis:
image: redis:7.4-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis:/data
app:
image: nextcloud:34-apache
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
depends_on:
db:
condition: service_healthy
volumes:
- nextcloud:/var/www/html
environment:
MYSQL_HOST: db
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER}
NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DOMAIN}
OVERWRITEHOST: ${NEXTCLOUD_DOMAIN}
OVERWRITEPROTOCOL: https
TRUSTED_PROXIES: 172.16.0.0/12
APACHE_DISABLE_REWRITE_IP: "1"
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 10G
cron:
image: nextcloud:34-apache
restart: unless-stopped
entrypoint: /cron.sh
depends_on:
db:
condition: service_healthy
volumes:
- nextcloud:/var/www/html
volumes:
db:
redis:
nextcloud:
Beberapa pilihan di file itu sengaja diambil, dan alasannya penting:
mariadb:11.4, bukan SQLite. Bawaan image Nextcloud memang SQLite, tapi itu hanya cocok untuk uji coba. MariaDB 11.4 adalah jalur LTS dan menangani banyak pengguna sekaligus tanpa tersendat.--transaction-isolation=READ-COMMITTEDadalah setelan yang diminta Nextcloud untuk MariaDB, dan varian baris-per-baris pada binlog menghindari konflik saat replikasi.- Kontainer
cronterpisah. Background job Nextcloud harus berjalan tiap 5 menit. Tanpa kontainer ini, mode bawaan cuma menjalankan tugas saat ada yang membuka situs, sehingga notifikasi dan pemindaian file terasa lambat. - Redis untuk locking. Inilah yang mencegah dua perangkat saling menimpa file yang sama. Kata kunci yang dicari nanti:
memcache.locking. - Port diikat ke
127.0.0.1:8080. Kontainer tidak pernah dibuka langsung ke internet; yang menghadap publik nanti cuma reverse proxy di host.
Satu peringatan jujur: nilai OVERWRITEHOST, OVERWRITEPROTOCOL, dan TRUSTED_PROXIES disalin ke config.php saat instalasi pertama dan tidak otomatis hilang kalau kamu hapus dari file compose. Jadi tulis dengan benar dari awal; kalau salah, perbaiki langsung di config/config.php di dalam volume.
Langkah 3: Nyalakan dan Tunggu Instalasi Pertama
cd /opt/nextcloud
docker compose up -d
docker compose logs -f app
Karena seluruh variabel database, admin, dan domain sudah lengkap, tidak ada wizard instalasi yang perlu kamu isi di browser. Tunggu 1–4 menit sampai log memunculkan pesan instalasi selesai, lalu keluar dari log dengan Ctrl+C. Cek statusnya:
docker compose ps
Yang kita cari: db berstatus healthy, dan app, redis, serta cron dalam keadaan running. Kalau app berputar-putar restart, sembilan dari sepuluh kasus penyebabnya adalah MYSQL_PASSWORD yang berbeda antara blok db dan blok app — dan itu memang mudah terjadi karena nilainya harus sama persis.
Langkah 4: Periksa Instalasi dengan occ
occ adalah alat baris perintah resmi Nextcloud. Semua perintah di bawah dijalankan sebagai user www-data di dalam kontainer:
docker compose exec -u www-data app php occ status
docker compose exec -u www-data app php occ config:system:get memcache.locking
docker compose exec -u www-data app php occ background:cron
docker compose exec -u www-data app php occ db:add-missing-indices
Empat hasil yang diharapkan:
statusmenampilkaninstalled: truebeserta nomor versi 34.x.memcache.lockingmenjawab\OC\Memcache\Redis— bukti Redis benar-benar dipakai, bukan diam-diam jatuh ke database.background:cronmemastikan mode tugas latar belakang memakai cron, sehingga kontainercrondi atas punya pekerjaan.db:add-missing-indicesmenutup peringatan indeks database yang biasanya muncul di halaman Administration settings → Overview.
Biasakan membuka halaman Overview itu setelah instalasi. Semua saran resmi Nextcloud berkumpul di situ, dan memperbaikinya saat masih satu kontainer jauh lebih mudah daripada setelah data menumpuk.
Langkah 5: Pasang Domain dan HTTPS
Karena app hanya mendengarkan di 127.0.0.1:8080, sekarang tugas reverse proxy. Polanya sama seperti saat kita membahas Nginx reverse proxy plus Certbot dan Cloudflare Tunnel: proxy di depan, aplikasi tetap di dalam localhost.
server {
listen 80;
server_name cloud.domainmu.com;
client_max_body_size 10G;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
Simpan sebagai /etc/nginx/sites-available/nextcloud, aktifkan dengan simbolik link, uji dengan nginx -t, lalu terbitkan sertifikatnya:
certbot --nginx -d cloud.domainmu.com
Dua hal yang sering terlewat di tahap ini. Pertama, X-Forwarded-Proto wajib dikirim; tanpa itu Nextcloud menganggap dirinya diakses lewat HTTP dan menghasilkan tautan berbagi yang salah. Kedua, TRUSTED_PROXIES harus mencakup IP gateway Docker (rentang 172.16.0.0/12 sudah menutupnya) supaya Nextcloud membaca IP asli pengunjung dari header, bukan IP proxy.
Kalau muncul layar Access through untrusted domain, artinya domain yang kamu pakai belum ada di trusted_domains. Tambahkan tanpa mengedit file apa pun:
docker compose exec -u www-data app php occ config:system:set trusted_domains 1 --value=cloud.domainmu.com
Langkah 6: Naikkan Batas Upload di Tiga Lapis
Ini penyebab paling umum keluhan “upload gagal di tengah jalan”. Batas ukuran file di Nextcloud itu berlapis, dan semuanya harus longgar:
- PHP — sudah kita set
PHP_UPLOAD_LIMIT: 10Gdi compose, yang mengaturupload_max_filesizedanpost_max_sizesekaligus. - Apache —
APACHE_BODY_LIMITbawaan image adalah 1 GiB (1073741824 byte). Kalau kamu ingin mengunggah file lebih besar dari itu, setAPACHE_BODY_LIMIT: "0"yang berarti tanpa batas. - Nginx —
client_max_body_size 10Gseperti di Langkah 5. Kalau angka ini tertinggal, permintaan besar akan ditolak sebelum sampai ke kontainer.
Setelah mengubah salah satunya, jalankan docker compose up -d app agar kontainer memuat ulang nilai barunya.
Langkah 7: Backup dan Update Tanpa Kehilangan Data
Backup Nextcloud itu dua bagian: database dan volume file. Keduanya harus diambil, karena mengembalikan salah satu saja tidak cukup. Backup database:
docker compose exec -T db mariadb-dump -u root -p"$MYSQL_ROOT_PASSWORD" \
--single-transaction nextcloud > backup-nextcloud-$(date +%F).sql
Untuk foldernya, arsipkan volume nextcloud_nextcloud (berisi config, data, dan aplikasi). Simpan kedua hasilnya di tempat lain — bukan di VPS yang sama. Pola backup terjadwalnya bisa memakai rclone + systemd timer yang sudah kita bahas sebelumnya.
Untuk update versi, naikkan satu major sekali jalan:
docker compose exec -u www-data app php occ maintenance:mode --on
docker compose pull
docker compose up -d
docker compose exec -u www-data app php occ upgrade
docker compose exec -u www-data app php occ maintenance:mode --off
Kalau occ upgrade bilang belum ada yang perlu dijalankan, itu kabar baik: image baru sudah menjalankan migrasinya sendiri. Kalau suatu hari kamu memulihkan data dari backup, jangan lupa panggil occ files:scan --all supaya Nextcloud mengenali ulang seluruh file di disk.
Kesalahan yang Paling Sering Terjadi
Access through untrusted domain— domain atau IP belum terdaftar ditrusted_domains. Perbaiki dengan perintahocc config:system:setdi Langkah 5.- Kontainer
apprestart berulang — password database tidak sama antaradbdanapp, atau database belum siap. Biarkanhealthcheckdandepends_on: condition: service_healthyyang mengatur urutan, jangan hapus blok itu. - Lupa memakukan tag versi — memakai
latestbisa membuat Nextcloud melompat major saat restart dan menolak naik. Pin34-apache, putuskan sendiri kapan update. - Background job tertinggal di mode AJAX — tandanya notifikasi email dan pemindaian file terasa lambat. Pastikan
occ background:cronsudah dijalankan.
Kesimpulan
Self-host Nextcloud di VPS dengan Docker Compose bukan proyek rumit: satu folder, satu file .env, satu docker-compose.yml, lalu reverse proxy untuk HTTPS. Sebagai imbalannya kamu punya cloud pribadi yang kapasitasnya mengikuti disk servermu, tanpa batas perangkat, dan tanpa data yang ikut dipindai pihak lain.
Jangan buru-buru memindahkan seluruh arsipmu di hari pertama. Pasang dulu, sinkronkan satu folder penting, buat backup otomatisnya, baru pindahkan sisanya perlahan. Cloud pribadi itu bukan soal langsung penuh, tapi soal kamu akhirnya tahu persis di mana filemu disimpan. Selamat mencoba, Sobat Online!

