Keamanan Siber Container Security untuk Home Server — Dari Docker Rootless sampai seccomp Ditulis oleh Adam Muiz 29 Jul 2026 Diperbarui: 06 Aug 2026 7 menit baca Beberapa bulan lalu, aku mulai serius memisahkan layanan di home server pakai Docker. Satu container buat web, satu buat database, satu lagi buat tooling kecil. Rasanya rapi, seperti apartemen dengan banyak kamar yang masing-masing punya fungsi sendiri. Tapi lama-kelamaan aku sadar: punya banyak kamar tidak otomatis membuat rumah itu aman. Kalau satu penghuni bisa membuka kamar lain atau bahkan keluar ke jalan utama, maka "terpisah" itu hanya ilusi. Itulah kenapa container security jadi topik yang wajib dipahami setelah kita nyaman pakai Docker. Container memang ringan dan praktis, tapi isolasinya berbeda dari virtual machine. Artikel ini adalah catatan dariku tentang tiga lapisan pertahanan yang paling mudah diterapkan: rootless container, capability drop, dan seccomp. Container Bukan VM — Isolasi Itu Tipis Salah satu kesalahpahaman umum adalah menganggap container sama kuat isolasinya dengan VM. Padahal container itu lebih miri process yang dibungkus dengan namespace dan cgroups. Mereka berbagi kernel yang sama dengan host. Kalau ada celah di kernel atau container runtime, escape dari container ke host bisa terjadi. Bayangkan container itu kaya kamar kos di rumah bersama. Masing-masing punya kunci sendiri, tapi semua berbagi dinding, pipa, dan sistem kelistrikan yang sama. Kamar itu memberi privasi, tapi bukan rumah terpisah. Kalau ada yang berhasil merusak dinding, dia bisa masuk ke area umum. Strategi terbaik bukan berhenti pakai container, tapi menambahkan lapisan pembatasan supaya setiap container hanya punya kemampuan minimum yang benar-benar dibutuhkan. Lapisan Pertama: Jangan Jalankan Container sebagai Root Defaultnya, proses di dalam container berjalan sebagai root (UID 0). Di dalam container memang terisolasi, tapi kalau terjadi escape, attacker langsung mendapatkan root di host. Itu seperti memberi kunci master apartemen ke setiap penghuni. Solusi paling sederhana: buat user biasa di dalam image, lalu pakai instruksi USER di Dockerfile. FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN addgroup -g 1001 -S appgroup && \ adduser -u 1001 -S appuser -G appgroup USER appuser CMD ["node", "server.js"] Dengan Dockerfile di atas, aplikasi berjalan sebagai UID 1001. Kalau attacker berhasil keluar dari container, dia tidak langsung jadi root. Langkah kecil, tapi dampaknya besar. Lebih jauh lagi, ada konsep rootless Docker atau rootless Podman. Di sini, daemon Docker itu sendiri tidak berjalan sebagai root. Container dijalankan oleh user biasa, bahkan UID 0 di dalam container sebenarnya dipetakan ke UID user di host. Ini mengurangi surface attack secara drastis. # Install rootless Docker (Debian/Ubuntu) dockerd-rootless-setuptool.sh install # Jalankan container rootless export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock docker run --rm -u 1000:1000 -v $HOME/project:/app:ro myapp Rootless container memang punya keterbatasan, misalnya tidak bisa bind ke port di bawah 1024 tanpa konfigurasi tambahan. Tapi untuk home server, biasanya kita bisa pakai reverse proxy di host yang forward ke port tinggi container. Lapisan Kedua: Capability Drop Di Linux, root punya banyak "superpower" yang disebut capabilities: bisa mengubah ownership file, membuka port raw, mengikat socket, dan lainnya. Secara default, container mendapatkan subset dari capabilities ini. Kita bisa membatasi dengan cara drop semua dulu, lalu add hanya yang benar-benar perlu. Prinsipnya mirip memberi izin ke aplikasi di ponsel: jangan kasih akses kamera, mikrofon, dan lokasi kalau aplikasi itu cuma kalkulator. # Drop semua capability, lalu tambahkan hanya yang dibutuhkan docker run -d \ --cap-drop=ALL \ --cap-add=NET_BIND_SERVICE \ --cap-add=CHOWN \ --name webapp \ myapp:latest Untuk container yang benar-benar tidak butuh hal spesial, cukup --cap-drop=ALL tanpa --cap-add apa pun. Aplikasi biasa seperti web server static atau worker queue seringnya tidak butuh capability sama sekali. Perintah di bawah ini menampilkan capabilities default yang diberikan Docker. Coba periksa sebelum mulai membatasi: docker run --rm -it ubuntu:24.04 capsh --print Lapisan Ketiga: Filter System Call dengan seccomp seccomp adalah fitur kernel Linux yang memungkinkan kita memfilter system call apa saja yang boleh dijalankan oleh sebuah process. Docker sudah punya profil seccomp default yang memblokir sekitar 44 system call berbahaya. Tapi banyak aplikasi modern tidak butuh semua system call yang masih diizinkan. Bayangkan seccomp kaya daftar akses di kantor: bukan cuma siapa yang boleh masuk, tapi juga apa saja yang boleh dilakukan di dalam. Kalau aplikasi hanya butuh membaca file, mendengarkan socket, dan menulis log, maka system call untuk memuat modul kernel atau mengubah memory mapping tidak perlu diizinkan. Contoh profil seccomp sederhana yang mengizinkan hanya syscall umum: { "defaultAction": "SCMP_ACT_ERRNO", "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_AARCH64"], "syscalls": [ { "names": [ "accept", "accept4", "bind", "brk", "clone", "close", "connect", "epoll_create", "epoll_create1", "epoll_ctl", "epoll_pwait", "epoll_wait", "exit", "exit_group", "fcntl", "fstat", "futex", "getcwd", "getpid", "getrandom", "getsockname", "getsockopt", "ioctl", "listen", "lseek", "mmap", "mprotect", "munmap", "nanosleep", "open", "openat", "poll", "read", "readv", "recvfrom", "recvmsg", "rt_sigaction", "rt_sigprocmask", "rt_sigreturn", "select", "sendmsg", "sendto", "setitimer", "setsockopt", "socket", "socketpair", "stat", "write", "writev" ], "action": "SCMP_ACT_ALLOW" } ] } Simpan sebagai seccomp-web.json, lalu jalankan container: docker run -d \ --security-opt seccomp=seccomp-web.json \ --cap-drop=ALL \ --name restricted-app \ myapp:latest Membuat profil seccomp sendiri memang butuh pemahaman mendalam. Cara praktis: mulai dari default Docker, lalu tambahkan pemblokiran secara bertahap sambil menjalankan integration test. Kalau aplikasi error, catat syscall yang dibutuhkan dan izinkan dengan hati-hati. Jaringan dan Volume: Batasi Jangkauan Container Isolasi tidak berhenti di process. Jaringan juga perlu diatur. Secara default, container bisa saling berkomunikasi lewat bridge network. Kalau satu container terkompromi, attacker bisa scan container lain di jaringan yang sama. Di home server, biasanya kita bisa membatasi dengan user-defined network atau bahkan tidak memberi akses jaringan sama sekali kalau tidak perlu. # Container tanpa akses jaringan (misalnya worker lokal) docker run -d --network none myworker # Container hanya bisa diakses lewat reverse proxy docker run -d --network my-private-net --name webapp myapp docker run -d --network my-private-net --name db postgres Volume juga harus diperhatikan. Hindari mount folder sensitif host ke container kecuali benar-benar diperlukan. Kalau memang perlu, gunakan opsi read-only (:ro) supaya container tidak bisa mengubah isinya. docker run -d \ -v /home/adam/project:/app:ro \ -v /home/adam/project/data:/app/data:rw \ myapp Praktik Tambahan yang Mudah Dilupakan Selain tiga lapisan di atas, ada beberapa kebiasaan kecil yang sering kucoba terapkan: Jangan expose port host kecuali perlu. Jangan pakai -p 3306:3306 untuk database kalau hanya container lain yang butuh akses. Gunakan internal network saja. Gunakan image minimal. alpine, distroless, atau slim mengurangi surface attack. Semakin sedikit tool di dalam image, semakin sedikit yang bisa disalahgunakan. Scan image secara berkala. Tool seperti trivy atau grype bisa mendeteksi CVE pada dependency image. Rotate secret. Jangan hardcode password, API key, atau token di image. Gunakan environment variable atau secret management. Update runtime dan kernel. Container security sangat bergantung pada kernel. Pastikan kernel host selalu up-to-date. Kesimpulan Container membuat deploy aplikasi di home server jadi lebih rapi, tapi rapi tidak sama dengan aman. Tiga langkah paling fundamental yang bisa langsung diterapkan adalah: jalankan container sebagai non-root, drop capability yang tidak perlu, dan pertimbangkan seccomp untuk membatasi system call. Ditambah dengan pengaturan jaringan dan volume yang ketat, kita sudah mengurangi risiko secara signifikan. Container security bukan tentang membuat server 100% tidak bisa ditembus — itu praktis tidak mungkin. Tapi tentang mempersulit attacker dengan lapisan-lapisan pembatasan, sehingga kalau satu container terkompromi, dampaknya tidak langsung meluas ke seluruh sistem. Di home server-ku sendiri, setiap container yang sekarang berjalan sudah aku arahkan pakai user non-root dan capability drop. Prosesnya pelan-pelan, tapi rasanya lebih tenang karena setiap "penghuni" apartemen digital ini hanya punya kunci untuk kamarnya sendiri. Kamu punya praktik container security yang rutin diterapkan di home server? Atau baru pertama kali dengar soal rootless Docker dan seccomp? Tulis di kolom komentar, aku senang belajar dari pengalamanmu juga.