Recently while working on Juju, we’ve started to use a tool called guiproxy. This allows us to talk to all of the various services that back our application in its live environment while proxying websocket requests to where they are going, as the proxy knows all of their addresses, while the GUI does not.

We’ve mostly used this for developing locally, where we start the GUI with make run and then run guiproxy. Running the GUI starts a pyramid server on port 6543, and guiproxy sets up a server running on :8042 that manages all of the proxying. You could visit the gui on :6543, but none of the websockets would reach the services, as it doesn’t know their addresses, so you visit the proxy at :8042, it proxies requests to the GUI and guides the websockets where they need to go.

However, I run things a little differently sort of by accident. Firstly, I have a Mac at home and don’t want to do what it takes to get the GUI up and running on this box, since that’d likely require vagrant. Secondly, as I wanted to work from anywhere and didn’t want to open up my home network so that I could access the GUI running on one of my other machines.

The end result is that I spun up a remote server — a linode, in this case — to work on. It also runs things like my IRC client and such. I set this up at I work on the GUI there, and that’s where it runs. For a while, I would just run guiproxy locally:

guiproxy -gui -env production -controller

This meant that I could run the GUI on my server, run the proxy locally, and visit it at

With our most recent sprint (which I’m writing from now), we needed to stand up a long-running instance of the GUI running a specific branch for some testing. I spent a bit of time thinking about just how to do this, but it turned out fairly easy: there’s no need to run the guiproxy on your local machine; you can run it wherever you want.

The end result is that I had the GUI running in the same way as any others would during development, but at a remote URL.

This took a bit of extra configuration

The server

We wanted this instance to be set up on a relatively pretty URL. I could have directed people to, but that wasn’t really desirable for our tests. We wanted something that had looked like we had tried. I have for short URLs and redirections, so I set up This is how that worked with nginx:

server {
        listen 80;
        listen [::]:80
        listen 443 ssl;
        listen [::]:443 ssl;
        ssl_certificate /etc/letsencrypt/live/;
        ssl_certificate_key /etc/letsencrypt/live/;


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

        location / {
                proxy_pass http://localhost:8042/;
                proxy_http_version 1.1;
                proxy_set_header Connection "upgrade";
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_read_timeout 1d;

This sets up a server running on using SSL. From there, it proxies requests to the guiproxy running in the background.

Running guiproxy

Running the guiproxy takes two additional bits of work to get this solution up and running.

  1. The GUI must be available from a different URL than from the proxy. only proxies requests to the proxy, so it’ll have to be something else. This can be localhost, of course, but can also be the fully qualified URL. I still have up and running, so I used that.
  2. We have SSL set up, but the GUI in dev mode expects the websocket to be insecure. We’ll need to manually upgrade that to WSS so that the browser doesn’t complain.
guiproxy -gui -env production -controller -config 'socket_protocol:"wss"'

I know this is a super specific case, but it just goes to show how to get all these parts talking together with tooling to help you along the way.