November 5, 2019

Bastel Proxy: HTTPS and reverse proxy for development environments

I tend to work on web applications and services which are interconnected. Different parts of the website and the services run as separate processes. In production something like NGINX does the HTTPS termination and unifies the services to a single domain. I found it useful to have HTTPS and a reverse proxy in my development environment too. Browsers complain about plain HTTPS sites and even disable certain features. Further, if your website is split across different processes and one part runs on http://localhost:8080 and other on http://localhost:8081, you can run into cross-domain issues. Also, I found it less error-prone to mirror the domain structure than having tons of localhost:{port} pointing to each other.

One option is to run a production reverse proxy like NGINX. However, it requires quite a bit of configuration and you have to provide it the HTTPS certificates etc. I wanted a solution specific for developments which tries to minimize setup time.

My solution: Bastel Proxy

Well, I built my own solution, called Bastel Proxy (GitHub). It tries to provide an easy to use HTTPS reverse for development. Currently, it works for Linux. Well, I checked Ubuntu 18.04 and Manjaro. It might need more work to support other distros.

Bastel Proxy gives HTTPS
Figure 1. Bastel Proxy gives HTTPS, certificates and a reverse proxy for development environments
Caution! Bastel Proxy Modifies Your System

Bastel Proxy modifies your system settings to achieve its goal. It installs it’s CA into the trust store of your operating system and browsers so that it can create trusted HTTPS certificates locally. It modifies /etc/hosts to make the specified domains pointing to 127.0.0.1. It uses iptables to redirect privileged HTTP and HTTPS ports to high-level ports.

Let me show what it does in a small walkthrough. Ensure you have Java 8 or newer installed, download Bastel Proxy and unpack it.

wget http://latest-download-link
tar xfv bastel-proxy-0.1.tar.gz
cd bastel-proxy

Then you run it:

gamlor@ubuntu:~/progs/bastel-proxy$ ./bastel-proxy.sh
Root certificates not yet installed. The certificates are installed into the trust store of the System, Chrome, and Firefox.
You can repeat this step later by starting Bastel Proxy with the --install-ca-cert flag
Hit enter to continue

Please enter your password to install CA to trust stores (Attempt 1 of 3)
// enter your precious root password
Import CA (do-not-trust-bastel-proxy-root) to distro's trust store
Reading package lists...
// SNIP

Import CA (do-not-trust-bastel-proxy-root) to Firefox and Chromium
CA imported to /home/gamlor/.mozilla/firefox/srw127r0.default-release
Import CA (do-not-trust-bastel-proxy-root) to the JDK

Installed Bastel-Proxy root-cert.crt certificate in known trust stores.
Starting proxy server

Failed to bind 80 443 ports. Will bind to high number port and redirect via iptables
Installed IP tables
To uninstall in case of an error:
iptables -t nat -D OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 42380
iptables -t nat -D OUTPUT -p tcp -d 127.0.0.1 --dport 443 -j REDIRECT --to-ports 42381

Ports: HTTP: 80 redirecting to 42380 HTTPS: 443 redirecting to 42381
Hosting sites:
https://bastel-proxy.local  ->  {:files ./}
Press enter to stop watching...

Now Bastel Proxy is up and running. Navigate to https://bastel-proxy.local in your Browser. It should accept the certificate and happily show the Bastel Proxy files. Bastel Proxy supports both, http and https connection.

Firefox trusting bastel proxy
Figure 2. Firefox trusting Bastel Proxy

You can inspect the /etc/hosts file to see what Bastel Proxy added:

gamlor@gamlor-t470p ~/bastel-proxy> cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       gamlor-t470p
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

#start Bastel-Proxy-entries

127.0.0.1       bastel-proxy.local
#end Bastel-Proxy-entries

Editing the Config

Once Bastel Proxy runs you can edit the config.edn file. Bastel Proxy reloads the config when it is saved. Note: If you add or remove a domain Bastel Proxy might prompt you again for the root/admin password to update the /etc/hosts file.

Here’s a example:

 :sites     {
             ; Serve my website locally. :preserve-host will forward the Host:gamlor.info header to the destination
             "gamlor.local"               {:proxy-destination "http://localhost:3000" :preserve-host true}
             "gamlor.local/blog"          {:proxy-destination "http://localhost:3001" :preserve-host true}
             ; API endpoint
             "api.gamlor.local"           {:proxy-destination "http://localhost:8080"}
             ; More API binding
             "api.gamlor.local/analytics" {:proxy-destination "http://localhost:8080"}
             ; Elastic Search Rest API
             "search.gamlor.local"        {:proxy-destination "http://localhost:9200"}
             ; And some files
             "cdn.gamlor.local/images"    {:files "/home/gamlor/Pictures/blog/"}
            }

Bastel Proxy will reload that config:

Configuration modified. Restarting proxy server
Restarting Bastel-Proxy
Failed to bind 80 443 ports. Will bind to high number port and redirect via iptables
Redirecting iptables already installed. Skipping installation
Ports: HTTP: 80 redirecting to 42380 HTTPS: 443 redirecting to 42381
Hosting sites:
https://gamlor.local  ->  {:proxy-destination http://localhost:3000, :preserve-host true}
https://gamlor.local/blog  ->  {:proxy-destination http://localhost:3001, :preserve-host true}
https://api.gamlor.local  ->  {:proxy-destination http://localhost:8080}
https://api.gamlor.local/analytics  ->  {:proxy-destination http://localhost:8080}
https://search.gamlor.local  ->  {:proxy-destination http://localhost:9200}
https://cdn.gamlor.local/images  ->  {:files /home/gamlor/Pictures/blog/}
Press enter to stop watching...

And bam these domains will work:

Domain and Subdomains just working
Figure 3. Domain and Subdomains just working

To stop the proxy hit enter. You can relaunch it any time again.

The Root Certificate

Bastel Proxy does install its CA certificate in common trust stores. However, it might missed one. For example, Java and NodeJS bring their own trusted certificates. You can import the created 'root-cert.crt' into the trust stores Bastel Proxy isn’t aware of.

Windows Support?

Windows is supported. It will use evaluation prompts instead of sudo. It also handles the certificates a bit different. It imports it into the user’s trust store used by Windows Chrome, Edge and IE. Then it sets the ImportEnterpriseRoots/security.enterprise_roots.enabled setting for Firefox so that it also reads CA certificates from the Windows Trust store.

Tags: Bastel Proxy Clojure Web Java