Index & Autoindex #
Ketika browser meminta sebuah direktori — URL-nya diakhiri / atau tidak ada ekstensi file — Nginx perlu memutuskan apa yang harus dikembalikan. Ada dua jalur yang tersedia: menampilkan file index yang sudah ditentukan, atau menampilkan daftar isi direktori secara otomatis. Dua directive yang mengontrol ini, index dan autoindex, terlihat sederhana tapi memiliki nuansa yang penting untuk dipahami.
Bagaimana Nginx Menangani Request ke Direktori #
Sebelum membahas directive secara spesifik, mari kita pahami alur yang terjadi ketika Nginx menerima request ke direktori:
flowchart TD
A["Request: GET /blog/\nNginx perlu menentukan\nfile yang dikembalikan"] --> B{"try_files digunakan?"}
B -- Ya --> C["try_files $uri $uri/ =404\nNginx cek $uri sebagai file dulu\nlalu $uri/ sebagai direktori"]
B -- Tidak --> D["Nginx langsung\ncek direktori"]
C --> E["URI = direktori?\nCari file index"]
D --> E
E --> F{"index.html ada\ndi direktori?"}
F -- Ya --> G["Redirect internal ke /blog/index.html\nKirim file tersebut"]
F -- Tidak --> H{"index.php ada?"}
H -- Ya --> I["Redirect internal ke /blog/index.php\nProses melalui FastCGI/PHP-FPM"]
H -- Tidak --> J{"autoindex on?"}
J -- Ya --> K["Generate HTML listing\ndaftar file di direktori"]
J -- Tidak --> L["Return 403 Forbidden\n(direktori ada tapi tidak bisa dilisting)"]Poin kritis yang sering membingungkan: 403 Forbidden, bukan 404, yang dikembalikan ketika direktori ada tapi tidak ada file index dan autoindex off. Ini sering membuat developer bertanya-tanya mengapa mereka mendapat 403 padahal direktori jelas-jelas ada.
Directive index #
index mendefinisikan daftar file yang dicari Nginx ketika request mengarah ke direktori. Nginx mencoba file-file dalam daftar secara berurutan, menggunakan yang pertama ditemukan.
Sintaks Dasar #
server {
root /var/www/html;
# Urutan pencarian: index.html → index.htm → index.php
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
Ketika GET / masuk:
- Nginx cek apakah
/var/www/html/index.htmlada → jika ya, gunakan ini - Jika tidak, cek
/var/www/html/index.htm→ jika ya, gunakan ini - Jika tidak ada satu pun → lanjutkan ke
try_filesberikutnya atau return error
Context yang Valid #
index bisa diletakkan di context http, server, atau location. Aturan inheritance berlaku: nilai di context yang lebih dalam menimpa context di atasnya.
http {
# Default global — berlaku untuk semua server block kecuali di-override
index index.html;
}
server {
server_name example.com;
root /var/www/example.com;
# Override di level server — berlaku untuk semua location di sini
index index.html index.htm;
location / {
# Mewarisi dari server: index.html index.htm
try_files $uri $uri/ =404;
}
location /app/ {
# Override khusus untuk direktori ini
index index.php index.html;
try_files $uri $uri/ =404;
}
location /admin/ {
# Override lagi — hanya mau index.php
index index.php;
try_files $uri $uri/ /admin/index.php;
}
}
Perhatian: index Memicu Internal Redirect #
Penting untuk dipahami: ketika Nginx menemukan file index, ia tidak langsung menyervisnya. Nginx melakukan internal redirect ke URI file tersebut, lalu memproses URI baru itu dari awal (mencari location block yang cocok lagi).
Request: GET /
↓
Nginx: Direktori! Cari file index.
Ketemu: /var/www/html/index.html
↓
Internal redirect ke: GET /index.html
↓
Nginx proses lagi: cari location block yang cocok dengan /index.html
↓
Nginx kirim file
Kenapa ini penting? Jika kita punya location khusus yang cocok dengan index.html, ia akan diproses:
server {
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location = /index.html {
# Ini AKAN dieksekusi ketika ada request GET /
# karena index directive memicu internal redirect ke /index.html
add_header Cache-Control "no-cache";
}
}
Directive autoindex #
autoindex mengaktifkan directory listing — Nginx akan menghasilkan halaman HTML yang menampilkan daftar file dan folder dalam direktori ketika tidak ada file index yang ditemukan.
Konfigurasi Dasar #
location /downloads/ {
root /var/www;
autoindex on;
# GET /downloads/ akan menampilkan listing:
# Index of /downloads/
# ../
# report-2024.pdf 12-Jan-2024 10:30 2.4M
# data-export.zip 05-Feb-2024 09:15 45.2M
# notes.txt 28-Feb-2024 14:22 1.2K
}
Opsi Tampilan autoindex #
location /files/ {
alias /data/shared/;
autoindex on;
# Format waktu — on: waktu lokal server, off: UTC/GMT
autoindex_localtime on;
# Format ukuran file:
# on: tampilkan bytes tepat (misal: 2457600)
# off: tampilkan dalam unit human-readable (misal: 2.4M)
autoindex_exact_size off;
# Format output — html (default), xml, json, jsonp
# json berguna untuk listing yang akan dikonsumsi oleh aplikasi
autoindex_format html;
}
autoindex dengan Format JSON #
Untuk file server yang diakses oleh aplikasi (bukan browser), format JSON lebih berguna:
location /api/files/ {
alias /data/shared/;
autoindex on;
autoindex_format json;
# GET /api/files/ akan mengembalikan:
# [
# {"name": "report.pdf", "type": "file", "mtime": "Tue, 12 Jan 2024 10:30:00 GMT", "size": 2457600},
# {"name": "data/", "type": "directory", "mtime": "Mon, 05 Feb 2024 09:00:00 GMT"}
# ]
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
}
Kasus Penggunaan yang Tepat untuk autoindex #
autoindex berguna untuk kasus-kasus spesifik, dan berbahaya jika diaktifkan sembarangan.
File Server Internal #
# Server file internal — hanya accessible dari jaringan kantor
server {
listen 80;
server_name files.internal.company.com;
root /data/shared;
# Batasi akses hanya dari jaringan internal
allow 10.0.0.0/8;
allow 192.168.0.0/16;
allow 172.16.0.0/12;
deny all;
location / {
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}
}
Mirror Repository #
Server mirror untuk distribusi software sering menggunakan autoindex:
server {
listen 80;
server_name mirror.example.com;
root /data/mirror;
location / {
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
# Tambahkan header agar bisa diakses dari subdomain
add_header Access-Control-Allow-Origin "https://example.com";
}
# Tapi blokir akses ke direktori konfigurasi
location ~ /\.git {
deny all;
}
}
Development Server #
# Server development — jangan gunakan di production!
server {
listen 8080;
server_name localhost;
root /home/developer/projects;
location / {
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}
}
Keamanan: Kapan autoindex Harus Dimatikan #
autoindex default adalah off — dan dengan alasan yang baik. Mengekspos daftar file bisa membocorkan informasi yang berharga bagi penyerang:
flowchart LR
A["autoindex on\ndi direktori publik"] --> B["Penyerang melihat\ndaftar file"]
B --> C["Menemukan:\n- backup-2024.sql\n- .env.backup\n- debug.log\n- private-key.pem"]
C --> D["Unduh file sensitif\natau gunakan informasi\nuntuk serangan lebih lanjut"]Direktori yang TIDAK BOLEH punya autoindex aktif:
- Root website production
- Direktori yang mengandung file konfigurasi
- Direktori upload user
- Direktori yang mengandung file PHP atau script
- Direktori dengan file backup atau log
Konfigurasi Keamanan yang Benar #
server {
root /var/www/html;
# Nonaktifkan autoindex secara eksplisit di seluruh site
# (default sudah off, tapi eksplisit lebih aman)
autoindex off;
location / {
try_files $uri $uri/ =404;
}
# Aktifkan hanya di satu subdirektori yang memang membutuhkan
location /public-downloads/ {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
# Batasi ekstensi file yang bisa terlihat (only allow safe files)
# Implementasi ini memerlukan logic di level aplikasi atau
# menggunakan modul seperti ngx_http_addition_module
}
# Pastikan direktori sensitif benar-benar tidak bisa di-browse
location /admin/ {
autoindex off; # Eksplisit, meskipun sudah default
# Tambahkan autentikasi
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
location /uploads/ {
autoindex off; # Selalu off untuk direktori upload
# Hanya izinkan ekstensi gambar
location ~* \.(jpg|jpeg|png|gif|webp|svg)$ {
expires 30d;
}
# Blokir semua tipe file lain di uploads
location ~ {
deny all;
}
}
}
Apa yang Terjadi Ketika Tidak Ada Index dan autoindex Off #
Ini adalah salah satu sumber kebingungan terbesar bagi pengguna Nginx baru:
Request: GET /gallery/
Kondisi:
- /var/www/html/gallery/ ada (direktori ada)
- /var/www/html/gallery/index.html TIDAK ada
- autoindex off (default)
Nginx mengembalikan: 403 Forbidden
403, bukan 404. Ini berarti: “Direktori ada, tapi saya tidak punya izin untuk memberitahumu apa yang ada di dalamnya (dan tidak ada halaman default untuk ditampilkan).”
Solusi Umum #
location /gallery/ {
# Opsi 1: Buat file index yang nyata
# (upload atau generate index.html di /var/www/html/gallery/)
# Opsi 2: Redirect ke halaman tertentu jika direktori diakses
# Gunakan try_files dengan named location
try_files $uri $uri/ @gallery_fallback;
}
location @gallery_fallback {
return 302 /gallery.html; # Redirect ke halaman gallery utama
}
# Opsi 3: Aktifkan autoindex jika memang aman
location /gallery/ {
autoindex on;
autoindex_exact_size off;
}
# Opsi 4: Blokir akses ke direktori tapi izinkan file
location /gallery/ {
# Izinkan akses file gambar langsung
location ~* \.(jpg|jpeg|png|gif|webp)$ {
expires 30d;
}
# Blokir akses langsung ke direktori
return 403;
}
Konfigurasi index untuk PHP Site #
Untuk website berbasis PHP, urutan index sering menjadi kritis:
server {
root /var/www/phpapp;
# Prioritaskan index.php — diproses oleh PHP-FPM
# index.html sebagai fallback untuk halaman statis
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Proses file PHP melalui PHP-FPM
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Jangan lewatkan ini — blokir akses file PHP di direktori upload!
location ~ /uploads/.*\.php$ {
deny all;
}
}
Mengkombinasikan index dan autoindex dengan Benar #
Ada satu pola yang sering salah dipahami: bagaimana index dan autoindex berinteraksi:
location /docs/ {
alias /opt/docs/;
# Jika ada index.html, tampilkan itu
index index.html;
# Jika TIDAK ada index.html, tampilkan listing
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}
Dengan konfigurasi ini, perilakunya adalah:
GET /docs/→ Nginx cek apakah/opt/docs/index.htmlada- Jika ada → tampilkan
index.html(autoindex tidak dipanggil) - Jika tidak ada → tampilkan directory listing (autoindex aktif)
Ini berguna untuk dokumentasi tree: folder yang punya index.html menampilkan halaman intro, folder yang tidak punya menampilkan daftar file.
Debugging Masalah index dan autoindex #
Cek Kenapa 403 Muncul #
# Cek apakah ada file index di direktori yang diakses
ls -la /var/www/html/gallery/
# Cek konfigurasi aktif untuk path tersebut
nginx -T | grep -A 20 "location /gallery"
# Cek error log
tail -f /var/log/nginx/error.log
# Output 403 biasanya menunjukkan salah satu:
# - directory index of "/var/www/html/gallery/" is forbidden → tidak ada index, autoindex off
# - "/var/www/html/gallery/" is forbidden → masalah permission
Verifikasi autoindex Berjalan #
# Request ke direktori — harus ada listing HTML
curl http://localhost/downloads/
# Atau cek di browser — search untuk "Index of /downloads/"
curl http://localhost/downloads/ | grep "Index of"
Cek MIME Type Listing #
Kadang browser tidak menampilkan listing dengan benar karena masalah MIME type:
curl -I http://localhost/downloads/
# Content-Type: text/html; charset=utf-8 ← harus begini
Membuat Tampilan autoindex Lebih Profesional #
Halaman autoindex bawaan Nginx sangat polos — tampilan tahun 90an dengan teks monospace dan tidak ada styling sama sekali. Meskipun kita tidak bisa mengubah template HTML-nya secara langsung di Nginx Community Edition, ada cara untuk mempercantik tampilan menggunakan modul addition atau dengan menyisipkan CSS/JS via header injection.
Cara yang Paling Mudah: Style Injection via Sub-Filter #
Jika Nginx dikompilasi dengan modul ngx_http_sub_module (aktif secara default di kebanyakan distribusi), kita bisa menyisipkan CSS ke halaman autoindex:
location /downloads/ {
alias /data/downloads/;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
# Sisipkan CSS untuk mempercantik tampilan
sub_filter '</head>' '<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; padding: 2rem; max-width: 900px; margin: 0 auto; }
h1 { font-size: 1.4rem; color: #334155; border-bottom: 2px solid #e2e8f0; padding-bottom: 1rem; margin-bottom: 1.5rem; }
table { width: 100%; border-collapse: collapse; }
td, th { padding: 0.5rem 1rem; text-align: left; }
tr:hover { background: #f8fafc; }
a { color: #3b82f6; text-decoration: none; }
a:hover { text-decoration: underline; }
</style></head>';
sub_filter_once on;
}
Alternatif: Gunakan Fancyindex Module #
Untuk tampilan yang benar-benar profesional, pertimbangkan modul ngx_fancyindex (perlu dikompilasi atau tersedia sebagai paket):
# Ubuntu/Debian
sudo apt install libnginx-mod-http-fancyindex
# Atau kompilasi dengan module (Nginx dari source)
./configure --add-module=/path/to/ngx-fancyindex
location /downloads/ {
alias /data/downloads/;
fancyindex on;
fancyindex_localtime on;
fancyindex_exact_size off;
fancyindex_header "/fancyindex-header.html";
fancyindex_footer "/fancyindex-footer.html";
fancyindex_name_length 255;
}
Konfigurasi Lengkap: File Server Internal Production #
Berikut konfigurasi file server internal yang bisa langsung digunakan untuk sharing file di jaringan kantor:
server {
listen 80;
server_name files.internal.example.com;
root /data/shared;
# ─── Keamanan: hanya jaringan internal ───────────────────
# Sesuaikan dengan subnet jaringan kantor kamu
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
# ─── Logging ──────────────────────────────────────────────
access_log /var/log/nginx/files-internal-access.log;
error_log /var/log/nginx/files-internal-error.log warn;
# ─── Directory listing untuk semua folder ─────────────────
location / {
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
# Tambahkan header yang berguna
add_header X-Robots-Tag "noindex, nofollow" always;
add_header Cache-Control "no-store" always;
}
# ─── Optimasi transfer untuk file besar ───────────────────
sendfile on;
sendfile_max_chunk 1m;
tcp_nopush on;
# ─── Timeout yang lebih panjang untuk file besar ──────────
# Default 60s mungkin tidak cukup untuk download file besar
proxy_read_timeout 300s;
send_timeout 300s;
# ─── Batasi ukuran upload jika ada ────────────────────────
client_max_body_size 0; # 0 = tidak ada batas (untuk file server)
# ─── Blokir file yang tidak perlu terlihat ────────────────
location ~ /\. {
deny all;
log_not_found off;
}
location ~* \.(sh|py|rb|php|pl|exe|bat|cmd)$ {
# Izinkan download tapi jangan eksekusi
default_type application/octet-stream;
add_header Content-Disposition "attachment";
}
}
indexmendefinisikan file yang dicari saat request ke direktori — Nginx mencoba file-file dalam daftar secara berurutan. File index yang ditemukan memicu internal redirect, bukan diservis langsung.autoindex onmengaktifkan directory listing — berguna untuk file server internal atau mirror, sangat berbahaya untuk website production.- Jika tidak ada file index dan
autoindex off: Nginx mengembalikan 403 Forbidden (bukan 404) — direktori ada tapi tidak ada yang bisa ditampilkan.- Format
autoindex_format jsonberguna ketika listing dikonsumsi oleh aplikasi, bukan browser.autoindex_exact_size off+autoindex_localtime onmembuat tampilan listing lebih mudah dibaca manusia.- Nonaktifkan
autoindexsecara eksplisit di level server, lalu aktifkan hanya di location tertentu yang memang membutuhkan — prinsip least privilege.- Untuk direktori upload, selalu tambahkan location block yang memblokir ekstensi berbahaya (
.php,.sh,.py) meskipun autoindex off.