{"id":699,"date":"2013-10-03T20:28:38","date_gmt":"2013-10-04T00:28:38","guid":{"rendered":"https:\/\/risacher.org\/jfdi\/?p=699"},"modified":"2016-08-23T11:48:56","modified_gmt":"2016-08-23T15:48:56","slug":"my-reverse-proxy","status":"publish","type":"post","link":"https:\/\/risacher.org\/jfdi\/2013\/10\/my-reverse-proxy\/","title":{"rendered":"my reverse-proxy"},"content":{"rendered":"<p><strong>UPDATE:<\/strong> There is a <a title=\"node-http-proxy does not support websockets on node 0.10.x\" href=\"https:\/\/risacher.org\/jfdi\/2013\/11\/node-http-proxy-does-not-support-websockets-on-node-0-10-x\/\">followup to this post<\/a>.<\/p>\n<p>Various people have asked me about my reverse proxy server, which I alluded to <a title=\"\u2018Reverse-Proxy Friendly\u2019\" href=\"https:\/\/risacher.org\/jfdi\/2013\/05\/reverse-proxy-friendly\/\">previously<\/a>.\u00a0 I&#8217;ve used Apache <a title=\"mod_proxy docs\" href=\"http:\/\/httpd.apache.org\/docs\/2.2\/mod\/mod_proxy.html\">mod_proxy<\/a>, and <a title=\"Perlbal on GitHub\" href=\"https:\/\/github.com\/perlbal\/Perlbal\">perlbal<\/a>, but now I do it with a 50-odd SLOC <a title=\"node.js\" href=\"http:\/\/nodejs.org\">node.js<\/a> program, which leans heavily on <a title=\"node-http-proxy on github\" href=\"https:\/\/github.com\/nodejitsu\/node-http-proxy\">node-http-proxy<\/a>.\u00a0 It&#8217;s too ad-hoc to be worth posting to GitHub, but its possibly worth describing for any other node.js types out there.<br \/>\n<!--more--><br \/>\nMainly it just consists of loading the dependencies and creating the appropriate proxy objects.\u00a0 The only remotely clever thing I did was to create an interface for reloading the routes on-the-fly, which allows me to add new applications without having to stop the existing service.\u00a0 (A &#8216;route&#8217;, in this context, means a mapping between a URL pattern and a backend application, usually described by some private port on localhost.)<\/p>\n<p>Considering that some of my applications use WebSockets, this means I can muck around with routes without disrupting users of the other applications.\u00a0 If I did the simpleminded thing (i.e. restarting the proxy server whenever I changed the routes) this would break the WebSocket connections each time the proxy server was restarted.<\/p>\n<p>Here&#8217;s what it looks like (<a href=\"https:\/\/risacher.org\/jfdi\/wp-content\/uploads\/2013\/10\/risacher_proxy.js\">proxy.js<\/a>):<\/p>\n<pre><code>\r\n\"use strict\";\r\n\/\/\r\n\/\/ proxy.js\r\n\/\/\r\nvar fs = require('fs'),\r\nhttp = require('http'),\r\nhttps = require('https'),\r\nutil = require('util'),\r\nhttpProxy = require('http-proxy');\r\n\r\n\/\/\r\n\/\/ Create a HTTP proxy server\r\n\/\/\r\nvar regular_proxy = httpProxy.createServer(81, 'localhost').listen(80);\r\n\r\nvar routes_file = fs.readFileSync(\"routes.json\");\r\nvar routes_json;\r\ntry {\r\n    routes_json = JSON.parse(routes_file);\r\n} catch (err) {\r\n    console.log(\"error parsing json file\\n\");\r\n    console.log(routes_file + \"\\n\");\r\n    console.log(routes_json + \"\\n\");\r\n    console.log(\"error was \"+ err.message + \"\\n\");\r\n}\r\n\r\n\/\/\r\n\/\/ Create a HTTPS proxy server\r\n\/\/\r\nvar ssl_proxy = httpProxy.createServer({\r\n    router: routes_json,\r\n    https: {\r\n\tkey: fs.readFileSync('\/etc\/apache2\/ssl\/risacher.org.key', 'utf8'),\r\n\tcert: fs.readFileSync('\/etc\/apache2\/ssl\/risacher.org.crt', 'utf8'),\r\n\tca: fs.readFileSync('\/etc\/apache2\/ssl\/gd_bundle.crt', 'utf8'),\r\n\tciphers: 'ECDHE-RSA-AES256-SHA:AES256-SHA:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM',\r\n\thonorCipherOrder: true\r\n    }\r\n}).listen(443);\r\n\r\nhttp.createServer(function (req, res) {\r\n    res.writeHead(200, { 'Content-Type': 'text\/plain' });\r\n    res.write('hello\\n');\r\n    var routes_file = fs.readFileSync(\"routes.json\");\r\n    var routes_json;\r\n    try {\r\n\troutes_json = JSON.parse(routes_file);\r\n\tssl_proxy.proxy.proxyTable.setRoutes(routes_json);\r\n    } catch (err) {\r\n\tres.write(\"error parsing json file\\n\");\r\n\tres.write(\"error was \"+ err.message + \"\\n\");\r\n    }\r\n    res.write(util.inspect(regular_proxy.proxy.proxyTable, false, 4));\r\n    res.end();\r\n}).listen(8000);\r\n<\/code><\/pre>\n<p>I then have a routes.json file which contains something like this:<\/p>\n<pre><code>\r\n{\r\n\"risacher.org\/ajaxterm\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:8022\",\r\n\"risacher.org\/term\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:8001\",\r\n\"risacher.org\/app2\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0    \"127.0.0.1:3000\",\r\n\"risacher.org\/app3\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:9001\",\r\n\"risacher.org\/app3\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0      \"127.0.0.1:8094\",\r\n\"risacher.org\/app4\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:3001\",\r\n\"risacher.org\/ghost\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:2368\",\r\n\"www.risacher.org\/app3\/\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:9001\",\r\n\".*\":\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"127.0.0.1:81\"\r\n}\r\n<\/code><\/pre>\n<p>So each app listens to some port on localhost, and proxy.js proxies them appropriately &#8211; ajaxterm listens on localhost:8022, and apache2 listens on localhost:81.\u00a0 I can reload the routes on-the-fly by doing <code>wget http:\/\/localhost:8000\/<\/code> (which is clumsy, but effective).\u00a0 I don&#8217;t do routing on unencrypted http traffic, since I don&#8217;t want to access any of my non-apache2 content unencrypted, but it would be pretty trivial to do so if you wanted.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>UPDATE: There is a followup to this post. Various people have asked me about my reverse proxy server, which I alluded to previously.\u00a0 I&#8217;ve used Apache mod_proxy, and perlbal, but now I do it with a 50-odd SLOC node.js program, which leans heavily on node-http-proxy.\u00a0 It&#8217;s too ad-hoc to be worth posting to GitHub, but [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,11,10],"tags":[],"class_list":["post-699","post","type-post","status-publish","format-standard","hentry","category-it","category-oss","category-personal"],"_links":{"self":[{"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/posts\/699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/comments?post=699"}],"version-history":[{"count":14,"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/posts\/699\/revisions"}],"predecessor-version":[{"id":1251,"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/posts\/699\/revisions\/1251"}],"wp:attachment":[{"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/media?parent=699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/categories?post=699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/risacher.org\/jfdi\/wp-json\/wp\/v2\/tags?post=699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}