Menyajikan Satu Konten di Clearnet dan .onion Tanpa Duplikasi

Situs clearnet dan versi .onion-nya tidak perlu dua folder. Satu direktori, dua blok nginx, satu root untuk keduanya, plus cara menghindari tautan absolut dan pihak ketiga yang membocorkan pengunjung.

Jean

1. November 2026November 1, 2026 · 11 Min. Lesezeit11 min read

Menyajikan Satu Konten di Clearnet dan .onion Tanpa Duplikasi

Situs Anda sudah jalan di internet biasa. Alamat .onion-nya juga sudah hidup. Lalu muncul pertanyaan yang terlihat sepele: berkas websitenya ditaruh di mana.

Jawaban yang paling sering dipakai adalah menyalin seluruh folder ke lokasi kedua. Satu folder untuk clearnet, satu folder untuk onion. Awalnya rapi. Setelah beberapa bulan, keduanya mulai berbeda diam-diam, dan Anda tidak tahu kapan tepatnya itu terjadi.

Artikel ini membahas cara menyajikan satu konten yang sama lewat dua alamat berbeda, dengan satu salinan berkas saja.


Masalahnya Bukan Sekadar Dua Kali Salin#

Kalau situs Anda hanya berisi lima halaman statis, menyalin folder memang tidak terasa berat. Masalah sebenarnya muncul dari sifat salinan itu sendiri: keduanya bisa berubah sendiri-sendiri.

Bayangkan urutan kejadian yang biasa terjadi.

Anda memperbaiki salah ketik di halaman depan. Anda menyalinnya ke folder onion. Beres.

Dua minggu kemudian Anda menambahkan halaman baru. Kali ini Anda lupa menyalinnya. Situs clearnet punya halaman itu, versi onion tidak. Pengunjung yang datang lewat Tor Browser mendapat halaman 404, dan Anda tidak akan pernah tahu kecuali ada yang melaporkannya.

Yang lebih berbahaya adalah perbaikan keamanan. Anda menambal satu celah di berkas JavaScript. Perbaikan itu mendarat di folder clearnet, tetapi folder onion masih menyimpan versi lama. Versi onion justru yang dipakai orang yang paling peduli privasi, dan justru versi itu yang Anda biarkan rentan.

Ada juga masalah ketiga yang jarang disadari. Berkas aset seperti CSS dan gambar sering disalin terpisah dari HTML. Ketika CSS berubah, Anda menyalinnya ke dua tempat dan membandingkan md5 untuk memastikan keduanya sama. Pekerjaan itu tidak salah, tetapi itu tanda bahwa struktur Anda memaksa Anda melakukan pekerjaan yang seharusnya tidak perlu ada.


Ide Dasarnya: Satu Root, Dua Pintu#

Nginx tidak peduli dari alamat mana permintaan datang. Ia hanya melihat header Host, lalu memilih blok server yang cocok, lalu mencari berkas di dalam root yang Anda tentukan.

Artinya, dua blok server yang berbeda boleh menunjuk ke root yang sama persis. Tidak ada salinan kedua. Berkas yang Anda ubah langsung berlaku untuk keduanya.

Yang berbeda bukan isinya, melainkan perilaku di sekelilingnya: cara akses, header yang dikirim, dan apa yang boleh dimuat halaman.

Mari kita susun dari awal.


Menyiapkan Satu Direktori Situs#

Kalau saat ini Anda punya dua direktori, gabungkan jadi satu. Pilih salah satu sebagai sumber kebenaran, lalu pindahkan sisanya.

sudo mv /var/www/html /var/www/situs
sudo chown -R www-data:www-data /var/www/situs
sudo chmod -R 755 /var/www/situs

Sesudah ini, hanya ada satu tempat yang perlu Anda sentuh ketika mengubah apa pun.


Membuat Onion Service yang Menunjuk ke Situs Itu#

Konfigurasi Tor ada di /etc/tor/torrc. Tambahkan blok berikut:

HiddenServiceDir /var/lib/tor/situs-saya/
HiddenServiceVersion 3
HiddenServicePort 80 127.0.0.1:8080

Perhatikan angka 127.0.0.1. Itu bukan detail sepele.

Kalau Anda menulis HiddenServicePort 80 8080, Tor akan meneruskan ke port itu di semua antarmuka. Selama port tersebut hanya dipakai Tor, dampaknya kecil. Tetapi begitu ada yang tahu, siapa pun di jaringan Anda bisa membuka situs itu tanpa lewat Tor, dan itu membatalkan seluruh alasan Anda memakai onion service.

Dengan 127.0.0.1, port tersebut hanya bisa dijangkau dari dalam mesin itu sendiri. Tor satu-satunya yang bisa masuk.

Siapkan direktorinya, lalu jalankan ulang Tor:

sudo mkdir -p /var/lib/tor/situs-saya
sudo chown -R debian-tor:debian-tor /var/lib/tor/situs-saya
sudo chmod 700 /var/lib/tor/situs-saya
sudo systemctl restart tor

Setelah Tor berjalan, alamat .onion Anda muncul di berkas hostname:

sudo cat /var/lib/tor/situs-saya/hostname

Simpan alamat itu. Kita akan memakainya dua kali lagi.


Nginx: Dua Blok, Satu Root#

Sekarang bagian intinya. Buka konfigurasi situs Anda, lalu susun dua blok server.

1. Blok Clearnet#

server {
    listen 443 ssl http2;
    server_name domain-anda.tld;

    ssl_certificate     /etc/letsencrypt/live/domain-anda.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain-anda.tld/privkey.pem;

    root /var/www/situs;
    index index.html;

    add_header Onion-Location http://alamatanda.onion$request_uri always;

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

Baris Onion-Location hanya ada di sini, tidak di blok onion. Alasannya sederhana: petunjuk itu berguna justru untuk orang yang belum berada di alamat onion. Kalau dipasang di situs onion, isinya menunjuk ke dirinya sendiri dan tidak ada gunanya.

2. Blok Onion#

server {
    listen 127.0.0.1:8080;
    server_name alamatanda.onion;

    root /var/www/situs;
    index index.html;

    add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'" always;

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

Tiga hal yang membedakan blok ini dari blok clearnet.

Pertama, ia hanya mendengarkan di 127.0.0.1:8080, sejalan dengan HiddenServicePort tadi.

Kedua, tidak ada ssl_certificate. Situs onion memang tidak memakai HTTPS, dan ini sering disalahpahami, jadi kita bahas di bagian sendiri di bawah.

Ketiga, ada Content-Security-Policy yang cukup ketat. Di situs onion, aturan ini bukan pengerasan tambahan, melainkan pengaman wajib. Kita akan kembali ke sini.

3. Uji Sebelum Dimuat Ulang#

sudo nginx -t

Kalau keluarannya menyebut syntax is ok dan test is successful, lanjutkan:

sudo systemctl reload nginx

Pakai reload, bukan restart, supaya koneksi yang sedang berjalan tidak terputus.


Kenapa Situs Onion Tidak Memakai HTTPS#

Ini pertanyaan yang hampir selalu muncul, dan jawabannya bukan "karena malas".

Sertifikat HTTPS diterbitkan oleh otoritas sertifikat publik. Otoritas itu memverifikasi bahwa Anda benar-benar menguasai domain yang Anda minta. Verifikasi tersebut dilakukan lewat DNS publik atau dengan mengakses berkas di server Anda dari internet terbuka.

Alamat .onion tidak ada di DNS publik. Ia hanya bisa diresolusi di dalam jaringan Tor. Karena itu tidak ada otoritas sertifikat yang bisa memverifikasinya, dan tidak ada sertifikat yang bisa diterbitkan.

Yang sering ditanyakan berikutnya: kalau begitu, apakah koneksi ke situs onion tidak terenkripsi?

Jawabannya, koneksi itu sudah terlindungi di lapisan yang berbeda. Trafik menuju onion service dienkripsi dari sisi pengunjung sampai ke server Anda, melewati enam relay: tiga dipilih oleh pengunjung, tiga dipilih oleh layanan Anda. Tidak ada satu pun dari keenam relay itu yang bisa membaca isinya, karena enkripsinya berjalan ujung ke ujung antara browser dan server.

Ada satu lapisan lagi yang sering terlewat. Alamat onion itu sendiri adalah kunci publik layanan Anda. Kalau ada pihak yang mencoba menyamar sebagai situs Anda, tanda tangannya tidak akan cocok dengan alamat tersebut, dan Tor Browser langsung menolaknya. Inilah sebabnya dokumentasi Tor Project menyebut layanan onion memberi keamanan setara HTTPS tanpa perlu sertifikat sama sekali.

Jadi jangan memasang pengalihan ke HTTPS di blok onion. Kalau Anda punya aturan global seperti return 301 https://$host$request_uri; untuk port 80, pastikan aturan itu tidak ikut mengenai permintaan onion. Blok onion di atas sengaja dibuat terpisah supaya tidak tersentuh aturan semacam itu.


Jebakan yang Paling Sering Terjadi: URL Absolut#

Ini bagian yang paling penting, dan paling mudah terlewat.

Misalkan di dalam HTML Anda ada baris seperti ini:

<img src="https://domain-anda.tld/assets/logo.png">

Di situs clearnet, baris itu berjalan normal. Tetapi ketika halaman yang sama dibuka lewat alamat .onion, browser tetap membaca alamat lengkap itu apa adanya. Ia akan menghubungi domain-anda.tld, bukan alamat onion Anda.

Akibatnya, ada dua hal buruk sekaligus. Pengunjung yang tadinya bersembunyi di balik Tor tiba-tiba menghubungi server Anda lewat jalur biasa, dan permintaan itu bisa dikenali. Dan situs Anda mengirim petunjuk kepada pengunjung bahwa versi onion-nya hanya tiruan.

Perbaikannya mudah, tetapi harus konsisten. Semua tautan dan semua aset di dalam situs harus memakai jalur relatif.

<img src="/assets/logo.png">

Dengan jalur relatif, browser menyelesaikannya terhadap alamat yang sedang dibuka. Di clearnet menjadi domain-anda.tld/assets/logo.png. Di onion menjadi alamatanda.onion/assets/logo.png. Keduanya benar, tanpa satu pun berkas tambahan.

Periksa seluruh situs Anda dengan:

grep -rn "https\?://domain-anda\.tld" /var/www/situs/

Kalau hasilnya kosong, berarti aman.


Jebakan Kedua: Pihak Ketiga#

Situs modern sering memuat berkas dari tempat lain: font dari Google, pustaka dari CDN, analitik dari penyedia pihak ketiga, komentar dari layanan pihak ketiga.

Semua itu di clearnet sudah jadi masalah privasi. Di situs onion, semuanya menjadi masalah yang jauh lebih serius.

Pikirkan apa yang terjadi: pengunjung memilih datang lewat Tor karena tidak ingin alamat IP-nya diketahui. Lalu halaman Anda memuat font dari server Google. Permintaan itu keluar dari Tor, membawa alamat IP pengunjung, dan terhubung langsung ke pihak ketiga.

Pengunjung memilih jalur privat, dan halaman Anda yang membocorkannya.

Karena itu situs onion sebaiknya memuat semuanya dari dirinya sendiri. Font, CSS, JavaScript, gambar. Semua di dalam satu direktori.

Content-Security-Policy di blok onion tadi menjaga ini secara otomatis. Dengan default-src 'self', browser akan menolak memuat apa pun dari domain lain, sehingga kebocoran seperti itu tidak mungkin terjadi walaupun Anda lupa.

add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'" always;

Kalau setelah dipasang ada bagian halaman yang rusak, itu bukan CSP-nya yang salah. Itu tanda halaman Anda memuat sesuatu dari luar, dan justru itu yang perlu diperbaiki.


Kalau Memang Ada Bagian yang Harus Berbeda#

Satu root bukan berarti tidak boleh ada perbedaan sama sekali.

Ada beberapa hal yang memang wajar dibedakan. Misalnya Anda ingin memasang penghitung kunjungan di clearnet tetapi tidak di onion. Atau Anda ingin menampilkan pengumuman kecil yang hanya berlaku untuk pengunjung onion.

Untuk kebutuhan seperti itu, jangan kembali ke dua folder. Cukup tambahkan satu variabel yang bisa dibaca di dalam halaman.

Variabel paling sederhana adalah header yang Anda tambahkan sendiri di blok onion:

server {
    listen 127.0.0.1:8080;
    server_name alamatanda.onion;

    root /var/www/situs;
    index index.html;

    add_header X-Served-Over onion always;

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

Anda tidak bisa membaca header itu dari HTML biasa, tetapi Anda bisa memakainya untuk hal lain, misalnya menyajikan berkas tambahan lewat satu blok location yang hanya ada di blok onion.

Untuk hal yang benar-benar butuh perbedaan isi, cara yang lebih rapi adalah memakai satu berkas tambahan:

# hanya di blok onion
location = /catatan-onion.js {
    alias /var/www/situs-khusus/catatan-onion.js;
}

Halaman memuat /catatan-onion.js seperti biasa. Di clearnet berkas itu tidak ada sehingga tidak terjadi apa-apa. Di onion ia tersedia. Tetap satu direktori utama, tetap satu sumber kebenaran, dan perbedaannya terlihat jelas karena hanya berupa satu blok kecil.


Alternatif yang Lebih Sederhana, dan Batasannya#

Kalau Anda benar-benar tidak butuh perbedaan header sama sekali, symlink sudah cukup:

sudo ln -s /var/www/html /var/www/onion

Nginx mengikuti symlink secara bawaan, jadi kedua direktori tampak identik dengan isi yang sama.

Tetapi cara ini punya dua batasan yang perlu disadari.

Pertama, Anda tidak bisa memberi header berbeda untuk masing-masing alamat, karena keduanya dilayani konfigurasi yang sama. Artinya Onion-Location akan ikut terkirim di situs onion, dan CSP yang ketat tidak bisa dipasang hanya di sana.

Kedua, symlink menyembunyikan masalah, bukan menyelesaikannya. Orang berikutnya yang membuka server Anda akan melihat dua direktori dan mengira keduanya perlu diurus, lalu salinan baru dibuat lagi. Kalau Anda memilih symlink, tinggalkan komentar di konfigurasi yang menjelaskan bahwa itu symlink dan bukan salinan.

Untuk situs yang serius, dua blok server dengan satu root tetap lebih jelas maksudnya.


Cara Memastikan Semuanya Benar#

Jangan percaya bahwa konfigurasi sudah jalan hanya karena nginx tidak mengeluh. Uji ketiga hal berikut.

1. Pastikan Situs Onion Melayani Halaman#

Dari dalam server:

curl -sI http://127.0.0.1:8080/ | head -5

Harus muncul HTTP/1.1 200 OK. Kalau keluar Connection refused, berarti port atau blok server belum benar.

2. Pastikan Onion-Location Hanya Ada di Clearnet#

curl -sI https://domain-anda.tld/ | grep -i onion-location
curl -sI http://127.0.0.1:8080/ | grep -i onion-location

Perintah pertama harus menampilkan header. Perintah kedua harus kosong.

3. Pastikan Tidak Ada Aset yang Mengarah ke Clearnet#

grep -rn "domain-anda\.tld" /var/www/situs/

Hasil yang kosong berarti tidak ada rujukan absolut ke domain clearnet.

Terakhir, uji dari mesin lain lewat Tor Browser. Buka alamat .onion Anda, lalu buka alat pengembang dan periksa tab jaringan. Semua permintaan seharusnya menuju alamat onion. Kalau ada satu saja yang menuju domain biasa, berarti masih ada yang terlewat.


Catatan Penting#

Jangan pernah membuka port onion ke semua antarmuka. Selalu 127.0.0.1 di HiddenServicePort dan di listen nginx. Ini satu baris yang membedakan antara onion service dan celah keamanan.

Cadangkan direktori HiddenServiceDir. Di dalamnya ada kunci privat alamat onion Anda. Kalau hilang, alamat itu hilang selamanya dan tidak bisa dibuat ulang. Salin ke tempat aman, dan jangan pernah menaruhnya di repositori publik.

Periksa ulang setiap kali menambah halaman. Kebiasaan memakai URL absolut mudah kembali tanpa sadar, terutama kalau Anda menyalin potongan kode dari tempat lain. Jalankan grep di atas sebelum mengunggah.

Ingat bahwa versi onion tidak otomatis lebih aman. Ia hanya menyembunyikan lokasi pengunjung. Kalau isinya masih memuat pihak ketiga, sebagian besar manfaatnya sudah hilang sebelum halaman selesai dimuat.


Penutup#

Duplikasi terasa lebih mudah di awal karena hanya perlu satu perintah salin. Yang tidak terlihat adalah biayanya: dua tempat yang bisa berbeda, dan satu di antaranya selalu tertinggal tanpa Anda sadari.

Satu direktori dengan dua pintu masuk menyelesaikan itu sekaligus. Anda mengubah berkas satu kali, dan perubahan itu berlaku untuk kedua alamat. Yang tersisa hanyalah memastikan tidak ada tautan yang mencoba keluar dari jalur yang sudah Anda bangun.

#nginx#onion#privacy#self-hosting#tor#tutorial

Written by

Comments

No comments yet. Start the conversation.

Contents

13 sections

  1. Masalahnya Bukan Sekadar Dua Kali Salin
  2. Ide Dasarnya: Satu Root, Dua Pintu
  3. Menyiapkan Satu Direktori Situs
  4. Membuat Onion Service yang Menunjuk ke Situs Itu
  5. Nginx: Dua Blok, Satu Root
  6. Kenapa Situs Onion Tidak Memakai HTTPS
  7. Jebakan yang Paling Sering Terjadi: URL Absolut
  8. Jebakan Kedua: Pihak Ketiga
  9. Kalau Memang Ada Bagian yang Harus Berbeda
  10. Alternatif yang Lebih Sederhana, dan Batasannya
  11. Cara Memastikan Semuanya Benar
  12. Catatan Penting
  13. Penutup