DEV Community

AmasiaNalbandian
AmasiaNalbandian

Posted on

Rerouting in nginx

Last week I decided to try some deep diving for back end in the Telescope repository. I found a very legitimate issue which I felt would be good to implement. Along the way I learned a lot about how nginx works.

Once I was able to understand how nginx uses the template files to redirect, I realized the logic behind the issue was actually simple. However, for someone who doesn't know what nginx is, it is not so easy to implement.

The Issue:

The task at hand is to redirect all calls from https://dev.telescope.cdot.systems/deploy and https://telescope.cdot.systems/deploy to the actual auto deploy port which is at https://dev.telescope.cdot.systems:4000 or https://telescope.cdot.systems:4000. The reason for this is that the port value is difficult to remember and not really user friendly. (Programmers can't be bothered to remember every port... I mean can you imagine?).

Understanding redirects in nginx

In order to redirect using nginx, we normally have code which looks like this:

 server {
    listen 80 default_server;
    server_name _;
    return 307 https://$host$request_uri;
  }
Enter fullscreen mode Exit fullscreen mode

This code block can be translated to:
listen to port 80, the default server.
server_name _; means that we can accept any requests on this port, and return 307 https://$host$request_uri; says to return 307 as the header(code 307 is temporary redirect), and then the route to redirect to. The variables host and request_uri are defined higher up in the template file.

This one is simple enough right?

So, why is it so difficult to redirect?

  1. The redirection can only be viewed on dev or stage. Currently I don't have privileges for this, and honestly I'm not too familiar with the code base to earn this.
  2. The redirection is for all route parametres, including anything followed after /deploy. For example, in this case we need it for /deploy/status and /deploy/log
  3. We need the same results when we navigate in the browser and in the command line.

Progress #1

Find out exactly where you need to use the redirect. I was lucky enough to have help and was told you don't really need to specify the server. So because this was a redirect, we can use /location to specify the route to redirect. I was also helped with finding the correct server to put this under.

Progress #2

The first attempt at the issue looked like this:

location /deploy/log {
    return https://${TELESCOPE_HOST}:4000/log;
}
Enter fullscreen mode Exit fullscreen mode

This worked... but it didn't work in the CLI. We quickly learned to use the proxy_pass method instead.

Progress #3

As you guessed it, we put it in as a proxy_pass.

location /deploy/log {
    proxy_cache_bypass 1;
    proxy_pass https://${TELESCOPE_HOST}:4000/log;
}
Enter fullscreen mode Exit fullscreen mode

So this worked!

Why wasn't this the final code?

It really isn't the best solution. For example if tomorrow we decide to put another route on the autodeploy servers /deploy/newroute will not work. We need to add another redirect. What happens when we have 20+ redirects now in this area?

Progress #4

To make this solution correct for future features on port 4000, I was provided with this solution:

# Redirect traffic from /deploy/* to the autodeployment server
location /deploy {
  proxy_cache_bypass 1;
  proxy_pass https://${TELESCOPE_HOST}:4000$request_uri
}
Enter fullscreen mode Exit fullscreen mode

This made absolute sense to me, and we went and tested it.. but the problem is request_uri picks up all the parameters after the server route. The redirect was actually going to https://${TELESCOPE_HOST}:4000/deploy/log. After reading, and searching some solutions, I found an article which actually worked to solve the same problem.

The third answer seems to be simple enough to explain:

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}
Enter fullscreen mode Exit fullscreen mode

so as long as you end the route you want to redirect with the slash /foo/ and the proxy_pass also ends in the slash, you can redirect all parameters in the route to the route you want.

Final code:

# Redirect traffic from /deploy/* to the autodeployment server
# extra slash for accepting all request_uri e.g. /deploy/status
location /deploy/ {
  proxy_cache_bypass 1;
  proxy_pass https://${TELESCOPE_HOST}:4000/;
}
Enter fullscreen mode Exit fullscreen mode

We made sure to write a note for future contributors. A little later we realized a similar redirection was already implemented in the same file - however, since we weren't too familiar with the redirection using nginx, we could not understand the intention, and overlooked it.

Top comments (1)

Collapse
 
csaltos profile image
Carlos Saltos

Great !! … thanks for sharing !! 👍😎