davestephens/ansible-nas: 107 Role untuk Bangun NAS Ubuntu

· Review

Artikel ini review repo orang lain — milik Dave Stephens (GitHub: davestephens/ansible-nas). Saya bukan maintainer dan tidak terafiliasi dengan proyek ini.

Motivasinya sederhana dan sangat relatable: author-nya bosan dengan update FreeNAS yang rusak, lalu memutuskan membangun NAS sendiri dari Ubuntu Server murni plus Ansible plus Docker. Hasilnya repo dengan 3.791 bintang (saat review) dan 107 role di direktori roles/.


Arsitektur: Satu Playbook, Ratusan Role

Inti seluruh sistem ini cuma satu file: nas.yml. Isinya daftar role yang dieksekusi berurutan, dikelompokkan dengan komentar pemisah.

---
- name: Ansible-NAS
  hosts: all

  roles:
    - role: ansible-nas-users
      tags: [ansible-nas-users, ansible-nas]

    - role: vladgh.samba.server
      tags: [samba, skip_ansible_lint]

    - role: geerlingguy.nfs
      tags: [nfs, skip_ansible_lint]

    - role: geerlingguy.docker
      vars:
        docker_apt_filename: download_docker_com_linux_ubuntu
      tags: [docker, skip_ansible_lint]

    - role: ansible-nas-general
    - role: ansible-nas-docker
    - role: logging
    - role: airsonic
    - role: apcupsd
    # ... 90+ role aplikasi berikutnya

Struktur ini penting dan sering disalahpahami oleh pemula: Ansible-NAS bukan aplikasi yang jalan sendiri, melainkan bootstrapper. Ia tidak bisa jalan di atas FreeNAS atau TrueNAS SCALE, karena justru dua sistem proprietary itu yang ingin ia ganti. Targetnya Ubuntu Server LTS dengan partisi yang sudah kamu buat sendiri.

Perhatikan tiga role pihak ketiga di awal playbook: vladgh.samba.server untuk file sharing, geerlingguy.nfs untuk share NFS, dan geerlingguy.docker yang menarik paket Docker langsung dari download.docker.com. Role pihak ketiga ini diambil dari Ansible Galaxy, bukan ditulis manual — pola yang tepat benar karena tidak reinvent the wheel untuk hal yang sudah matang.

Tag sebagai pemicu eksekusi

Tanpa tag, satu ansible-playbook nas.yml akan membangun 90+ container sekaligus. Dengan tag, kamu bisa menambah satu service tanpa menyentuh yang lain. Ini yang membedakan Ansible-NAS dari docker-compose.yml raksasa yang biasa dipakai orang: perubahan bersifat inkremental, bukan all-or-nothing.

ansible-playbook nas.yml --tags jellyfin          # hanya Jellyfin
ansible-playbook nas.yml --tags docker,samba      # hanya fondasi
ansible-playbook nas.yml --skip-tags minecraft    # lewati yang berat
ansible-playbook nas.yml --tags ansible-nas       # hanya layer inti

Variabel Terpusat: Titik Tunggal Konfigurasi

Semua path dan credential default terkumpul di group_vars/all.yml dengan banner yang tegas:

### DO NOT EDIT THIS FILE!
### Add your customisations to inventories/<your_inventory>/group_vars/nas.yml

Pola ini yang benar. group_vars/all.yml adalah milik upstream, customization kamu ditaruh di inventories/<namamu>/group_vars/nas.yml. Kalau nanti repo di-update, file kamu tidak tertimpa.

Isi default-nya cukup detail:

ansible_nas_user: david
ansible_nas_email: [email protected]
ansible_nas_domain: example.com

samba_shares_root: /mnt/Volume3
downloads_root: "{{ samba_shares_root }}/downloads"
movies_root:    "{{ samba_shares_root }}/movies"
tv_root:        "{{ samba_shares_root }}/tv"
torrents_root:  "{{ samba_shares_root }}/torrents"
music_root:     "{{ samba_shares_root }}/music"
books_root:     "{{ samba_shares_root }}/books"
roms_root:      "{{ samba_shares_root }}/roms"

Perhatikan pola penamaan: setiap path diturunkan dari satu variabel akar (samba_shares_root). Kalau kamu pindah ke hard disk 8 TB, cukup ubah satu baris dan seluruh 16+ path ikut bergeser. Ini kerapian yang sering diabaikan di playbook rumahan.


Anatomy Satu Role: Jellyfin Sebagai Contoh

Setiap role aplikasi punya struktur yang konsisten. Ini roles/jellyfin/tasks/main.yml secara dipotong:

- name: Start jellyfin
  block:
    - name: Create Jellyfin Directories
      ansible.builtin.file:
        path: "{{ item }}"
        state: directory
      with_items:
        - "{{ jellyfin_config_directory }}"

    - name: Jellyfin Docker Container
      community.docker.docker_container:
        name: "{{ jellyfin_container_name }}"
        image: "{{ jellyfin_image_name }}:{{ jellyfin_image_version }}"
        pull: true
        volumes:
          - "{{ jellyfin_config_directory }}:/config:rw"
          - "{{ jellyfin_movies_directory }}/movies:{{ jellyfin_movies_permissions }}"
          - "{{ jellyfin_music_directory }}/music:{{ jellyfin_music_permissions }}"
        ports:
          - "{{ jellyfin_port_http }}:8096"
        env:
          TZ: "{{ ansible_nas_timezone }}"
          PUID: "{{ jellyfin_user_id }}"
          PGID: "{{ jellyfin_group_id }}"
        restart_policy: unless-stopped
        memory: "{{ jellyfin_memory }}"
        labels:
          traefik.enable: "{{ jellyfin_available_externally | string }}"
          traefik.http.routers.jellyfin.rule: "Host(`{{ jellyfin_hostname }}.{{ ansible_nas_domain }}`)"
          traefik.http.routers.jellyfin.tls.certresolver: "letsencrypt"
          traefik.http.services.jellyfin.loadbalancer.server.port: "8096"
          homepage.group: Media
          homepage.name: Jellyfin

Tiga hal yang layak ditiru dari role ini:

1. Nol nilai hardcoded di dalam task. Semua angka — nama container, versi image, port, PUID/PGID, limit memori — adalah variabel. Ini yang membuat role bisa di-reuse tanpa edit.

2. Traefik dikonfigurasi lewat label, bukan file terpisah. Setiap aplikasi yang punya ansible_nas_available_externally = true otomatis dapat subdomain + sertifikat Let’s Encrypt wildcard. Tidak ada effort SSL per aplikasi. Ini evolusi dari reverse proxy terpisah yang harus dirawat manual.

3. restart_policy: unless-stopped dan memory limit. Dua baris kecil yang sering luput di compose amateur. Memory limit mencegah satu service yang boros RAM menjatuhkan seluruh host.

Label homepage.group dan homepage.name juga berarti dashboard Homepage terisi otomatis begitu service hidup. Detail kecil, tapi justru efek yang membuat orang bertahan di playbook.


Inventaris: 107 Role dalam 6 Golongan

Saya kelompokkan 107 role-nya supaya tidak hanya jadi daftar panjang:

GolonganContohJumlah
Fondasisamba, nfs, docker, ansible-nas-users/general/docker6
Mediajellyfin, plex, emby, navidrome, komga, tautulli~12
*arr stacksonarr, radarr, lidarr, prowlarr, bazarr, overseerr, sabnzbd, nzbget10
Produktivitasnextcloud, paperless_ng, calibreweb, wallabag, mealie, firefly, freshrss, miniflux~15
Infrastrukturtraefik, portainer, netdata, glances, grafana, prometheus, loki, promtail, healthchecks~12
Lain-laingitea, gitlab, code-server, minecraft-server, virtual_desktop, esphome, homeassistant, octoprint~50

Nama-nama di kategori produktivitas sering diabaikan orang yang cuma bangun NAS untuk media, tapi justru di situ nilai Infrastructure as Code terasa paling nyata: paperless_ng untuk arsip dokumen fisik, firefly untuk keuangan pribadi, wallabag untuk baca-nanti. Semuanya dapat domain sendiri dan SSL sendiri.

Ada satu fitur yang layak disebut secara terpisah: role hello_world. Directory-nya ada di roles/ tapi tidak muncul di README. Ini role contoh/template — pola umum di Ansible Galaxy untuk membantu kontributor baru memulai role sendiri tanpa menebak struktur direktori (tasks/, defaults/, handlers/, meta/).


Batasan yang Perlu Dijujurkan

Developer-nya sendiri menyebut apa yang tidak dikerjakan, dan ini justru tanda proyek yang matang:

  1. Tidak membuat partisi disk. Dengan alasan yang sangat benar — salah partisi berarti data hilang, dan itu kejadian yang jarang serta destruktif. Partisi cukup sekali seumur server, tidak perlu diotomasi.
  2. Butuh Ubuntu Server LTS. Tidak bisa jalan di atas TrueNAS SCALE, OpenMediaVault, atau NAS vendor. Kalau kamu sudah punya NAS berbasis ZFS atau Btrfs, proyek ini bukan pilihan yang tepat.
  3. Tidak semua aplikasi sudah matang. Role lama seperti couchpotato dan sickchill sudah usang (proyeknya sudah dihentikan upstream), sementara romm dan threadfin relatif baru.

Kapan Repo Ini Cocok untuk Kamu

Sangat cocok kalau:

  • Kamu sudah nyaman dengan terminal dan *arr stack.
  • Kamu punya satu atau dua server dan bosan copy-paste docker-compose.yml.
  • Kamu mau bisa destroy and rebuild seluruh server dari nol dalam 30 menit.
  • Kamu sebenarnya butuh Samba + NFS + DDNS + Traefik dan ingin semuanya selesai dalam satu perintah.

Kurang cocok kalau:

  • Butuh ZFS, deduplication, atau RAID seperti yang lazim dipakai NAS.
  • Sistem operasi yang bukan Ubuntu.
  • Rebuild-from-scratch adalah skenario yang jarang kamu hadapi.

Verdict

Ansible-NAS bukan NAS, tapi peralatan untuk membangun NAS. Dan di sinilah review ini menemukan sesuatu yang jarang diucapkan: sebagian besar playbook homelab di luar sana ditulis untuk demo di YouTube, bukan untuk dipakai dua tahun. Yang membuat repo ini berbeda bukan jumlah role-nya — 107 role itu angka marketing. Yang membuatnya layak dipakai adalah tiga keputusan arsitektur yang sering dilewati orang:

  1. Tag pada setiap role → perubahan inkremental, bukan total.
  2. Pemisahan group_vars/all.yml vs inventories/*/group_vars/ → update upstream tidak menimpa customization lokal.
  3. Nol hardcoding di dalam task → setiap service bisa ditukar, dipindah, atau diskalakan tanpa menyentuh playbook.

Kalau kamu punya beberapa server dengan isi yang tumpang tindih, waktu yang dihabiskan untuk migrasi ke model seperti ini akan balik modal dalam hitungan minggu. Kalau cuma satu server kecil, manual docker compose masih lebih ringan dan tidak perlu belajar Ansible.


Repo: davestephens/ansible-nas — lisensi MIT, 3.791 bintang. Dokumentasi: ansible-nas.io