Reverse Proxy from HTTP to HTTPS with Apache

The other day, I had problem accessing an HTTPS site from a Python script. Since I had no time to spend figuring out why (it was for a personal project anyway), I decided to make a reverse proxy using Apache. However, unlike the commonly setup reverse proxy, this one is to make an HTTPS site available as HTTP site.

This is what I needed to put in my Apache config.

<VirtualHost 127.0.0.1:12345>
    ...
    SSLProxyEngine On
    ProxyPass / https://that.secure.site/
    ProxyPassReverse / https://that.secure.site/
    ....
</VirtualHost>

I also had to enable mod_proxy and mod_ssl which can be done easily (on Debian based system) by running the following command

# a2enmod proxy ssl

Then reload or restart Apache

# service apache2 reload

The most important bit in the config above is SSLProxyEngine On. Without this the proxy would not work!

Reverse Proxy dari HTTP ke HTTPS

Masalah lain yang saya temui setelah nyadar kalo tempat saya naro file RSS blog gak bisa diakses adalah ternyata si jadul PlanetPlanet kombinasi dg Python 2.7 punya masalah saat nyedot data dari situs https ini. Entah apakah ini kasus spesifik atau ngga, saya kurang tau 😛

Saat saya menjalankan si PlanetPlanet, tiba2 dia ngeluarin exception di bawah ini.

Traceback (most recent call last):
  File "/anu/itu/planet/feedparser.py", line 1893, in _open_resource
    return opener.open(request)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1215, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1174, in do_open
    h.request(req.get_method(), req.get_selector(), req.data, headers)
  File "/usr/lib/python2.7/httplib.py", line 958, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python2.7/httplib.py", line 992, in _send_request
    self.endheaders(body)
  File "/usr/lib/python2.7/httplib.py", line 954, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python2.7/httplib.py", line 814, in _send_output
    self.send(msg)
  File "/usr/lib/python2.7/httplib.py", line 776, in send
    self.connect()
  File "/usr/lib/python2.7/httplib.py", line 1161, in connect
    self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
  File "/usr/lib/python2.7/ssl.py", line 381, in wrap_socket
    ciphers=ciphers)
  File "/usr/lib/python2.7/ssl.py", line 141, in __init__
    ciphers)
TypeError: must be _socket.socket, not _socketobject

Nanya2 oom google ngga membawa hasil yang menggembirakan. Berhubung saya lagi males ngecek2 lebih jauh, jadi saya putuskan tuk bikin situs blog ini tersedia dalam modus http juga walau cuma bisa diakses dari localhost 😛 ehh ternyata sepertinya si wordpress kekeuh sekali https, tetap https (duh). Berhubung yg ini gagal, saya coba cara lain dg bikin reverse proxy aja 😀 proxy yang membungkus situs https tuk disediakan dalam http.

Kira2 begini konfigurasinya

<VirtualHost 127.0.0.1:12345>
    ...

    SSLProxyEngine On
    ProxyPass / https://fajran.web.id/
    ProxyPassReverse / https://fajran.web.id/

    ...
</VirtualHost>

Nyalakan modul mod_proxy dan mod_ssl dan restart/reload si apache.

Konfigurasi di atas mirip dg cara membuat reverse proxy biasa, namun ada bagian penting yang ngga boleh kelupaan ditulis: SSLProxyEngine On. Tanpa ini, proxy dari http ke https ngga bisa jalan.

Sindikasi

Setelah lama tak ditengok, ternyata tempat saya naro RSS feeds tuk blog ini tak bisa diakses 😀 dann ternyata itu gara2 lupa ngubah konfigurasi Apache saat dulu upgrade dari versi 2.2 ke 2.4 (doh)!

Satu hal yang berubah di Apache 2.4 itu adalah cara ngasih izin akses ke sebuah direktori. Kalau sebelumnya make yang berikut

Order allow,deny
allow from all

Apache versi lebih baru berubah menjadi seperti yang berikut ini

Require all granted

Kirain semua udah diubah saat dulu upgrade, ternyata ada yang ketinggalan T_T

Konfigurasi Apache2 di Debian

Sebelum salah sangka, tulisan saya ini tidak menjelaskan cara mengatur Apache2. Namun membahas gaya atau pendekatan cara melakukan konfigurasi Apache 2 di Debian dan keluarganya. Silakan baca dokumentasi Apache 2 atau tutorial yang lain kalau Anda sedang mencari tahu bagaimana cara membuat/mengatur konfigurasi untuk Apache 2.

Oya, semua yang saya tulis ini hanya berasal dari pengamatan saya. Mohon koreksi jika ada yang salah.

***

Debian (dan turunannya) punya cara unik untuk mengatur virtual host di apache2. Konfigurasi apache2 yang normalnya ada pada berkas bernama httpd.conf diubah dan dipecah2 sedemikian sehingga menjadi fleksibel dan mudah diotomasi dengan skrip.

Konfigurasi utama apache2 di Debian bukanlah ada pada berkas httpd.conf, melainkan pada berkas apache2.conf yang terletak di bawah direktori /etc/apache2. Dari konfigurasi utama ini, berkas2 konfigurasi lainnya diikutsertakan (include) sehingga menjadi satu konfigurasi utuh. Berkas2 lainnya itu antara lain adalah

  • /etc/apache2/mods-enabled/*.load dan /etc/apache2/mods-enabled/*.conf yang isinya adalah konfigurasi untuk mengaktifkan modul dan konfigurasi untuk modul tersebut.
  • /etc/apache2/httpd.conf yang ditujukan tuk konfigurasi tambahan yang dibuat oleh sang admin.
  • /etc/apache2/ports.conf yang berisi daftar port yang ingin dibuka. Isinya tentu saja hanya baris2 konfigurasi dg keyword Listen
  • /etc/apache2/conf.d/[^.#]* yang isinya juga konfigurasi lain2 yg dipecah2 ke dalam beberapa berkas
  • /etc/apache2/sites-enabled/[^.#]* yang isinya adalah konfigurasi virtual host

Kalau ngeliat direktori /etc/apache2, maka di dalamnya akan terdapat pasangan direktori sites-available dan sites-enabled dan juga mods-available dan mods-enabled. Apa artinya “available” dan bedanya dengan “enabled” yang disebut dari konfigurasi utama apache2.conf?

Singkatnya begini. Yang berada di dalam direktori “available” adalah konfigurasi siap pasang sedangkan konfigurasi yang benar2 dipasang dan aktif berada di dalam direktori “enabled”.

Kalau ngeliat isi direktori “enabled”, maka Anda akan menjumpai symbolic link ke berkas-berkas yang ada pada direktori “available”. Ya, konfigurasi sebenarnya memang diletakkan di bawah direktori “available”. Dari sekian konfigurasi yang ada di bawah direktori tersebut, konfigurasi yang benar-benar dipakai akan “ditunjuk” atau “dipilih” dengan cara membuat symbolic linknya dari direktori “enabled”.

Sebagai contoh jika Anda ingin membuat konfigurasi sebuah virtual host. Maka buatlah sebuah berkas di dalam direktori sites-available yang berisi konfigurasi virtual host yang Anda inignkan. Jika sudah dan Anda ingin mengaktifkannya, buatlah symbolic link ke berkas tersebut dari dalam direktori sites-enabled.

Untuk lebih mempermudah pengaturan, Debian telah menyiapkan dua buah skrip untuk membantu urusan mengaktifkan dan menonaktifkan virtual host, yaitu skrip bernama a2ensite dan a2dissite (yang sepertinya berasal dari kalimat “apache 2 enable site” dan “apache 2 disable site”). Cara menggunakannya adalah seperti berikut ini.

$ sudo a2ensite nama-berkas-virtual-host

Begitu pula tuk urusan modul. Konfigurasi siap pakai berada di dalam mods-available dan yang dipakai ada dalam mods-enabled. Skrip pembantunya juga ada, yaitu a2enmod dan a2dismod.

Salah satu keuntungan dengan melakukan pemecahan berkas konfigurasi menjadi berkas-berkas yang lebih kecil adalah mempermudah otomasi. Sebagai contoh jika kita ingin menonaktifkan modul php5, maka kita cukup mengetikkan sudo a2dismod php5 dan reload apache2nya. Tidak perlu susah-susah mengedit berkas konfigurasi, mencari baris konfigurasi yang berhubungan dengannya, lalu melakukan penghapusan atau penambahan tanda komentar.

Selain itu, terkait juga dengan instalasi dan penghapusan paket yang berisi modul tuk Apache2, skrip instalasi tidak perlu susah-susah melakukan parsing konfigurasi yang ada untuk memasang atau menghapus konfigurasi yang terkait dengan modul tersebut. Karena pada dasarnya yang perlu dilakukan hanyalah menambah dan menghapus berkas pada direktori mods-available.

***

Gaya penanganan berkas konfigurasi yang dipecah-pecah seperti ini memang dapat membuat bingung “pendatang baru”. Namun, menurut saya, kalau sudah paham apa maksudnya, maka gaya seperti ini dapat membuat hidup lebih mudah =D

Content negotiation di Apache

Sepertinya ini fitur yang jarang dipake orang *sotoy* Sangat berguna jika ingin menyediakan dokumen berbeda-beda sesuai dengan keinginan pelanggan pengguna (browser). Sebagai contoh kasus, dokumen dalam bahasa Indonesia akan dikirim jika browser yang digunakan meminta bahasa Indonesia.

Caranya: aktifkan modul mod_mime dan mod_negotiation. Lalu buat aturan di .htaccess atau di konfigurasi utama seperti berikut (ini contoh tuk satu dokumen dalam bahasa berbeda).

Options Multiviews
AddLanguage id .id
AddLanguage en .en
LanguagePriority

Lalu, sediakan berkas dengan akhiran .id dan .en yang tentu saja memiliki isi yang berbeda (misalnya index.html.id dan index.html.en).

Contoh penggunaan nyata bisa dicek di http://labs.fajran.web.id/p/sources.list/. Kalau make Firefox bahasa Indonesia, nanti bahasa yang dipakai langsung diubah jadi bahasa Indonesia =D

Sebenernya trik ngubah bahasa tampilan di aplikasi kecil di atas itu juga melibatkan javascript. Daripada susah2 ngejelasin, mending intip aja langsung kodingan javascriptnya ya =D.

Dah dulu ah.. ntar kepanjangan. Selamat berbingung ria =P