Rerouting in nginx 
Published: 2021-11-20 03:45:35

Last week I decided to try some deep diving for back end in the Telescope repository. I found a very [legitimate issue](https://github.com/Seneca-CDOT/telescope/issues/2383) 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;
  }
```

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;
}
```

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;
}
```

So this worked!

![](https://giphy.com/clips/theoffice-the-office-peacock-tv-show-G96zgIcQn1L2xpmdxi)

#### 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
}
```

 

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](https://serverfault.com/questions/379675/nginx-reverse-proxy-url-rewrite) 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!
}
```

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/;
    }

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.