Root & Alias

Root & Alias #

root dan alias adalah dua directive yang tampaknya melakukan hal yang sama — menentukan dari mana Nginx membaca file — tapi cara mereka membentuk path file sangat berbeda. Ini adalah salah satu sumber kebingungan terbesar di Nginx, bahkan bagi pengguna yang sudah cukup berpengalaman. Salah memilih antara keduanya mengakibatkan 404 yang membingungkan, atau lebih berbahaya, file diservis dari lokasi yang salah.

Artikel ini akan membedah perbedaan keduanya secara mendalam sampai kita benar-benar paham kapan harus menggunakan yang mana.

Inti Perbedaan: Cara Pembentukan Path #

Perbedaan fundamental antara root dan alias adalah apa yang ditambahkan ke URI untuk membentuk path file:

root:   path file = nilai root  +  URI penuh
alias:  path file = nilai alias +  URI setelah bagian location yang cocok

Mari kita lihat dengan contoh konkret menggunakan request GET /assets/style.css:

Dengan root #

location /assets/ {
    root /var/www;
}
URI:      /assets/style.css
root:     /var/www
          ─────────────────────────────
          /var/www  +  /assets/style.css
          = /var/www/assets/style.css

Seluruh URI (/assets/style.css) ditambahkan ke nilai root. Segmen /assets/ ikut masuk ke path.

Dengan alias #

location /assets/ {
    alias /var/www/static/;
}
URI:           /assets/style.css
location:      /assets/
                          ──────────── ini yang tersisa setelah mencocokkan location
URI sisa:      style.css
alias:         /var/www/static/
               ─────────────────────────────────────
               /var/www/static/  +  style.css
               = /var/www/static/style.css

Bagian URI yang cocok dengan location (/assets/) digantikan dengan nilai alias. Hanya sisa URI setelah bagian yang cocok yang ditambahkan.


Diagram Perbandingan Langsung #

flowchart LR
    subgraph ROOT["Dengan root"]
        direction TB
        R1["Request: GET /assets/style.css"]
        R2["location /assets/\n  root /var/www;"]
        R3["Path = /var/www + /assets/style.css"]
        R4["→ /var/www/assets/style.css"]
        R1 --> R2 --> R3 --> R4
    end

    subgraph ALIAS["Dengan alias"]
        direction TB
        A1["Request: GET /assets/style.css"]
        A2["location /assets/\n  alias /var/www/static/;"]
        A3["Cocokkan /assets/ → sisa: style.css"]
        A4["Path = /var/www/static/ + style.css"]
        A5["→ /var/www/static/style.css"]
        A1 --> A2 --> A3 --> A4 --> A5
    end

Perbedaan hasilnya jelas: root menghasilkan /var/www/assets/style.css, alias menghasilkan /var/www/static/style.css. Untuk request yang sama!


Tabel Perbandingan Komprehensif #

# ─── Setup ────────────────────────────────────────────────────────────────────
# File di filesystem:
# /var/www/html/about.html
# /var/www/assets/style.css
# /var/www/assets/logo.png
# /data/uploads/report.pdf
# /opt/docs/html/guide.html
KonfigurasiRequestPath yang dicariCocok?
root /var/www/html; di location /GET /about.html/var/www/html/about.html
root /var/www; di location /assets/GET /assets/style.css/var/www/assets/style.css
root /var/www/assets; di location /assets/GET /assets/style.css/var/www/assets/assets/style.css❌ (double /assets/)
alias /var/www/assets/; di location /assets/GET /assets/style.css/var/www/assets/style.css
alias /data/uploads/; di location /files/GET /files/report.pdf/data/uploads/report.pdf
alias /opt/docs/html/; di location /docs/GET /docs/guide.html/opt/docs/html/guide.html

Kapan Menggunakan root #

Gunakan root ketika struktur direktori di filesystem mencerminkan struktur URL. Ini adalah kasus yang paling umum untuk static site:

server {
    root /var/www/mysite;
    # Struktur filesystem:
    # /var/www/mysite/
    # ├── index.html        → GET /
    # ├── about.html        → GET /about.html
    # ├── images/           → GET /images/...
    # │   ├── logo.png      → GET /images/logo.png
    # │   └── banner.jpg    → GET /images/banner.jpg
    # ├── css/
    # │   └── style.css     → GET /css/style.css
    # └── js/
    #     └── app.js        → GET /js/app.js

    location / {
        try_files $uri $uri/ =404;
    }
}

root juga ideal di level server block (bukan di dalam location), karena akan diwarisi oleh semua location block:

server {
    listen 80;
    server_name example.com;

    # Satu root untuk seluruh site
    root /var/www/example.com;

    location / {
        try_files $uri $uri/ =404;
    }

    location /blog/ {
        # Mewarisi root dari server block
        # GET /blog/post.html → /var/www/example.com/blog/post.html ✓
        try_files $uri $uri/ =404;
    }

    location /gallery/ {
        # Mewarisi root dari server block
        # GET /gallery/photo.jpg → /var/www/example.com/gallery/photo.jpg ✓
        try_files $uri =404;
    }
}

Kapan Menggunakan alias #

Gunakan alias ketika nama direktori di filesystem berbeda dari URL path, atau ketika kita memetakan URL ke lokasi yang sama sekali terpisah:

Kasus 1: Nama direktori berbeda dari URL #

server {
    root /var/www/myapp;

    # File ada di /var/www/assets/ tapi diakses lewat /static/
    # Dengan root /var/www/assets; → dicari di /var/www/assets/static/ ← SALAH!
    # Dengan alias /var/www/assets/; → dicari di /var/www/assets/ ← BENAR!
    location /static/ {
        alias /var/www/assets/;
        # GET /static/style.css → /var/www/assets/style.css ✓
    }
}

Kasus 2: File di lokasi terpisah dari web root #

server {
    root /var/www/myapp;

    # Upload files disimpan di storage terpisah (SSD cepat, NFS mount, dsb)
    location /uploads/ {
        alias /mnt/storage/user-uploads/;
        # GET /uploads/2024/photo.jpg → /mnt/storage/user-uploads/2024/photo.jpg
    }

    # Dokumentasi API di direktori berbeda
    location /api-docs/ {
        alias /opt/api-documentation/html/;
        # GET /api-docs/auth.html → /opt/api-documentation/html/auth.html
    }

    # Aset shared untuk multiple proyek
    location /shared-assets/ {
        alias /var/www/shared/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Kasus 3: alias tidak bisa di server block #

Ini adalah batasan penting: alias hanya valid di dalam location block. Tidak ada alias di level server atau http:

# INVALID — alias di server block:
server {
    alias /var/www/html;  # Error! alias hanya valid di location
    ...
}

# VALID — alias hanya di location:
server {
    root /var/www/myapp;  # root di server block: OK

    location /docs/ {
        alias /var/www/docs/;  # alias di location: OK
    }
}

Jebakan Trailing Slash #

Masalah trailing slash adalah kesalahan yang paling sering terjadi dengan alias. Aturannya sederhana: trailing slash di location dan alias harus konsisten.

Skenario 1: Keduanya ada trailing slash ✅ #

location /files/ {    # ada trailing slash
    alias /data/;     # ada trailing slash
}
# GET /files/photo.jpg → /data/photo.jpg ✓
# GET /files/        → /data/ ✓

Skenario 2: Keduanya tidak ada trailing slash ✅ #

location /files {    # tidak ada trailing slash
    alias /data;     # tidak ada trailing slash
}
# GET /files/photo.jpg → /data/photo.jpg ✓
# GET /files         → /data ✓

Skenario 3: Tidak konsisten — location ada, alias tidak ❌ #

location /files/ {   # ada trailing slash di location
    alias /data;     # TIDAK ada trailing slash di alias
}
# GET /files/photo.jpg → /dataphoto.jpg ← SALAH! tidak ada pemisah

Skenario 4: Tidak konsisten — location tidak ada, alias ada ❌ #

location /files {    # TIDAK ada trailing slash di location
    alias /data/;    # ada trailing slash di alias
}
# GET /files/photo.jpg → /data//photo.jpg ← double slash!
# Kebanyakan OS handle double slash dengan benar,
# tapi ini tetap adalah konfigurasi yang salah dan bisa menimbulkan masalah
flowchart TD
    A["Konfigurasi alias"] --> B{"location /path/\nada trailing slash?"}
    B -- Ya --> C{"alias /dir/\nada trailing slash?"}
    B -- Tidak --> D{"alias /dir\nada trailing slash?"}
    C -- Ya --> E["✅ Konsisten\nBenar"]
    C -- Tidak --> F["❌ Tidak konsisten\nPath salah terbentuk"]
    D -- Tidak --> G["✅ Konsisten\nBenar"]
    D -- Ya --> H["❌ Tidak konsisten\nDouble slash"]

Rekomendasi: selalu gunakan pola dengan trailing slash di keduanya (location /path/ + alias /dir/) — ini paling intuitif dan paling sering digunakan.


Jebakan Umum dengan root di dalam location #

Ini adalah kesalahan yang paling sering dilakukan oleh Nginx pengguna baru:

# SITUASI: file ada di /var/www/assets/style.css
# TUJUAN: file bisa diakses via /static/style.css

# ❌ SALAH — menggunakan root:
location /static/ {
    root /var/www/assets;
    # Nginx akan mencari: /var/www/assets/static/style.css
    # File tersebut TIDAK ADA — yang ada /var/www/assets/style.css
    # → 404 Not Found yang membingungkan
}

# ✅ BENAR — menggunakan alias:
location /static/ {
    alias /var/www/assets/;
    # Nginx akan mencari: /var/www/assets/style.css ✓
}

# ✅ ALTERNATIF — menggunakan root dengan path yang benar:
# Buat direktori /var/www/assets/static/ dan simpan file di sana
location /static/ {
    root /var/www/assets;
    # Nginx akan mencari: /var/www/assets/static/style.css ✓ (jika file ada di sana)
}

alias dengan try_files #

Menggunakan alias bersama try_files memerlukan perhatian khusus. try_files bekerja berdasarkan URI, bukan path alias:

location /files/ {
    alias /data/uploads/;

    # try_files menggunakan $uri (URI asli dari browser)
    # → /data/uploads/report.pdf (setelah alias mapping)
    try_files $uri =404;
}

Untuk kasus yang lebih kompleks dengan directory listing fallback:

location /docs/ {
    alias /opt/docs/html/;

    # Coba file → coba direktori → 404
    try_files $uri $uri/ =404;
}

Untuk named location fallback dengan alias:

location /media/ {
    alias /data/media/;

    # Jika file tidak ada, alihkan ke handler
    try_files $uri @media_not_found;
}

location @media_not_found {
    return 404 '{"error": "Media file not found"}';
    add_header Content-Type application/json always;
}

Regex location dengan alias #

Ketika location menggunakan regex, alias bisa memanfaatkan capture group dari regex:

# Misal: file disimpan per tahun di /data/media/YYYY/
# dan diakses via /gallery/YYYY/filename
location ~* ^/gallery/(\d{4})/(.+)$ {
    alias /data/media/$1/$2;
    # GET /gallery/2024/photo.jpg → /data/media/2024/photo.jpg
}

Ini adalah fitur yang kuat tapi perlu hati-hati karena rentan terhadap path traversal jika capture group tidak divalidasi. Untuk kasus ini, lebih aman menggunakan try_files dengan fallback error:

location ~* ^/gallery/(\d{4})/([a-zA-Z0-9._-]+)$ {
    # Regex capture group sudah membatasi karakter yang diizinkan
    alias /data/media/$1/$2;
    try_files "" =404;
}

Pola Konfigurasi Praktis #

Multi-Location dengan Campuran root dan alias #

server {
    listen 443 ssl;
    server_name example.com;

    # root global — untuk file di public/ dir
    root /var/www/example.com/public;

    # ─── HTML, JS, CSS utama ────────────────────────────────
    location / {
        try_files $uri $uri/ /index.html;  # SPA fallback
    }

    # ─── Asset dengan versioning hash ───────────────────────
    location /assets/ {
        # File ada di /var/www/assets/ (di luar root)
        alias /var/www/assets/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # ─── File upload user ───────────────────────────────────
    location /uploads/ {
        alias /mnt/storage/uploads/;
        # Hanya izinkan akses file gambar
        location ~* \.(jpg|jpeg|png|gif|webp|svg)$ {
            expires 7d;
            add_header Cache-Control "public";
        }
        # Blokir semua file lain (PHP, HTML, dsb)
        location ~ {
            deny all;
        }
    }

    # ─── Dokumentasi (direktori terpisah) ───────────────────
    location /docs/ {
        alias /opt/docs/html/;
        try_files $uri $uri/ =404;
    }

    # ─── API → backend ──────────────────────────────────────
    location /api/ {
        proxy_pass http://localhost:3000/;  # trailing slash penting di sini!
        # Dengan trailing slash: GET /api/users → backend menerima GET /users
        # Tanpa trailing slash: GET /api/users → backend menerima GET /api/users
    }
}

Debugging: Kenapa File Tidak Ditemukan? #

Ketika mendapatkan 404 yang membingungkan, alat paling berguna adalah mengaktifkan logging detail dan memahami path mana yang sedang Nginx cari.

Verifikasi Path yang Dibentuk Nginx #

Cara paling langsung adalah menggunakan variabel Nginx untuk melihat path yang dibentuk:

# Sementara di development — JANGAN di production
server {
    root /var/www/html;

    location /assets/ {
        alias /var/www/static/;

        # Log path yang dicari untuk setiap request
        # (hanya untuk debugging, matikan setelah selesai)
        add_header X-Debug-Path $document_root$uri;
        # X-Debug-Path akan menunjukkan path yang dibentuk root
        # (alias tidak langsung tercermin di $document_root)
    }
}

Cara yang lebih informatif: gunakan error_log dengan level debug:

# Set error log ke debug di nginx.conf sementara
error_log /var/log/nginx/debug.log debug;

# Lalu request URL yang bermasalah dan lihat log
tail -f /var/log/nginx/debug.log | grep "open()"

# Contoh output yang berguna:
# [debug] ... open() "/var/www/static/photo.jpg" (file tidak ada)
# [debug] ... open() "/var/www/html/assets/photo.jpg" (file tidak ada)
# → dari sini kita tahu path mana yang sedang dicari

Checklist Debugging root vs alias #

Ketika menghadapi 404 yang tidak seharusnya, ikuti checklist ini:

# 1. Cek apakah file benar-benar ada di path yang diharapkan
ls -la /var/www/static/photo.jpg         # untuk alias
ls -la /var/www/html/assets/photo.jpg    # untuk root di location /assets/

# 2. Cek izin akses Nginx
sudo -u www-data ls /var/www/static/photo.jpg
# Jika "Permission denied" → masalah izin, bukan path

# 3. Cek konfigurasi Nginx yang aktif
nginx -T | grep -A 10 "location /assets"
# Pastikan root atau alias yang kamu lihat sesuai ekspektasi

# 4. Cek dengan curl dan lihat header debug
curl -v http://example.com/assets/photo.jpg 2>&1 | grep -E "< HTTP|< X-Debug"

# 5. Cek error log
tail -f /var/log/nginx/error.log | grep "open()"

Kesalahan Path yang Paling Umum #

Situasi: file ada di /var/www/static/photo.jpg
         diakses via GET /assets/photo.jpg

❌ Konfigurasi salah (menggunakan root):
   location /assets/ { root /var/www/static; }
   → Nginx cari: /var/www/static/assets/photo.jpg  ← DOUBLE ASSETS
   → File tidak ada → 404

✅ Konfigurasi benar (menggunakan alias):
   location /assets/ { alias /var/www/static/; }
   → Nginx cari: /var/www/static/photo.jpg ✓

✅ Konfigurasi benar (menggunakan root dengan struktur direktori yang benar):
   location /assets/ { root /var/www; }
   → Nginx cari: /var/www/assets/photo.jpg ✓
   → File harus ada di /var/www/assets/photo.jpg (bukan /var/www/static/)

Panduan Cepat: root atau alias? #

Gunakan decision tree ini ketika ragu:

flowchart TD
    A["Perlu menentukan\nlokasi file?"] --> B{"Nama direktori di disk\nsama dengan URL path?"}
    B -- Ya --> C["Gunakan root\ndi server block\n(diwarisi semua location)"]
    B -- Tidak --> D{"File di root\nyang sudah ada?"}
    D -- Ya --> E["Ubah struktur direktori\nagar cocok dengan URL,\nlalu gunakan root"]
    D -- Tidak --> F["Gunakan alias\ndi dalam location block"]
    F --> G["Pastikan trailing slash\nkonsisten antara\nlocation dan alias"]

Ringkasan #

  • root: path file = nilai root + URI penuh. Seluruh URI ditambahkan ke root.
  • alias: path file = nilai alias + URI setelah bagian location yang cocok. Bagian URI yang cocok dengan location digantikan oleh alias.
  • Gunakan root di level server block untuk kasus umum — diwarisi semua location tanpa perlu mendefinisikan ulang.
  • Gunakan alias di dalam location block ketika nama direktori di disk berbeda dari URL, atau ketika file ada di lokasi yang terpisah dari web root.
  • Trailing slash harus konsisten: location /path/ + alias /dir/ atau location /path + alias /dir — jangan campur.
  • alias tidak valid di level server block — hanya di location.
  • Jika melihat 404 yang tidak masuk akal dengan root, coba ubah ke alias — kemungkinan besar itulah masalahnya.

← Sebelumnya: Virtual Host   Berikutnya: Index & Autoindex →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact