| 
     | 
    @@ -0,0 +1,272 @@ | 
  
    
     | 
     | 
  
    # Virtual Hosts on nginx (CSC309) | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    When hosting our web applications, we often have one public IP | 
    
     | 
     | 
  
    address (_i.e.,_ an IP address visible to the outside world) | 
    
     | 
     | 
  
    using which we want to host multiple web apps. For example, one | 
    
     | 
     | 
  
    may wants to host three different web apps respectively for | 
    
     | 
     | 
  
    `example1.com`, `example2.com`, and `example1.com/images` on | 
    
     | 
     | 
  
    the same machine using a single IP address. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    **How can we do that?** Well, the good news is Internet browsers | 
    
     | 
     | 
  
    send the domain name inside HTTP requests and all we need to do | 
    
     | 
     | 
  
    is to parse the requested domain name and URL and then route the | 
    
     | 
     | 
  
    HTTP request to the actual web server. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    **Oh, do I really need to parse HTTP requests?** You can if you  | 
    
     | 
     | 
  
    really want to, but there are lots of tools and technologies that | 
    
     | 
     | 
  
    readily do this for you. In this tutorial, we walk you through | 
    
     | 
     | 
  
    how you can use nginx to _proxy_ multiple web applications. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ## Install nginx | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### CDF @UofT | 
    
     | 
     | 
  
    We have prepared pre-copmiled binaries for your.  | 
    
     | 
     | 
  
    You need to download [nginx.tar.gz](http://www.cs.toronto.edu/~soheil/csc309/nginx.tar.gz) | 
    
     | 
     | 
  
    and uncompress it: | 
    
     | 
     | 
  
    ```sh | 
    
     | 
     | 
  
    $ wget http://www.cs.toronto.edu/~soheil/csc309/nginx.tar.gz && tar -xvzf nginx.tar.gz | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    - It creates an nginx directory for you. The config file | 
    
     | 
     | 
  
      is in `nginx/conf/nginx.conf`. | 
    
     | 
     | 
  
    - We have provided a script named `nginx` in the directory. | 
    
     | 
     | 
  
      To run `nginx`, go to the `nginx` directory (`cd nginx`) and | 
    
     | 
     | 
  
      run `./nginx ...`. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Ubuntu | 
    
     | 
     | 
  
    Install `nginx` using `apt-get`: | 
    
     | 
     | 
  
    ```sh | 
    
     | 
     | 
  
    $ sudo apt-get install nginx | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    **Notes:** | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    - The part of the `nginx`'s config file we need resides in `/etc/nginx/sites-enabled/default`. | 
    
     | 
     | 
  
    - To edit the config file or run `nginx`, you need to use `sudo`.  | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Mac OS  | 
    
     | 
     | 
  
    Install [`homebrew`](http://brew.sh), and then install `nginx` using `brew`: | 
    
     | 
     | 
  
    ```sh | 
    
     | 
     | 
  
    $ brew install nginx | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    **Notes:** | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    - `nginx`'s config file is in `/usr/local/etc/nginx/nginx.conf`. | 
    
     | 
     | 
  
    - To edit the config file or run `nginx`, you need to use `sudo`: | 
    
     | 
     | 
  
      `sudo nano /usr/local/etc/nginx/nginx.conf` and | 
    
     | 
     | 
  
      `sudo nginx ...` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ## Configuration | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 1 -- Booting Servers for Virtual Hosts | 
    
     | 
     | 
  
    Write three different node applications running on different ports | 
    
     | 
     | 
  
    (say 8080, 8181, 8282) on your machine. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 2 -- Configure nginx's Port | 
    
     | 
     | 
  
    To do so, you need to edit your `nginx` config file. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    In the config file, find the `server` section: | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       80; | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
           ... | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    **If you're using CDF**, make sure you change `80` to a vacant port number | 
    
     | 
     | 
  
    (ask for one from your instructor). If not, you can keep using `80` or | 
    
     | 
     | 
  
    change the port if you will. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    **Test nginx** | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    1. Run `./nginx` on CDF, or run `sudo nginx` on your local machine. | 
    
     | 
     | 
  
    2. Open the browser and log on to `localhost:$PORT` (replace `$PORT` with | 
    
     | 
     | 
  
       the port number you configured for `nginx`). | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 3 -- Configure / | 
    
     | 
     | 
  
    Let say we want to configure `nginx` to route requests for | 
    
     | 
     | 
  
    `/`, `/blog`, and `/mail`, respectively onto | 
    
     | 
     | 
  
    `localhost:8080`, `localhost:8181`, and `localhost:8282`. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
                      +--- host --------> node.js on localhost:8080 | 
    
     | 
     | 
  
                      | | 
    
     | 
     | 
  
    users --> nginx --|--- host/blog ---> node.js on localhost:8181 | 
    
     | 
     | 
  
                      | | 
    
     | 
     | 
  
                      +--- host/mail ---> node.js on localhost:8282 | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    To route `/`, you need to edit your `nginx` config file. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    In the config file, find the `server` section: | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       80; | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
           ... | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    This section is simply telling `nginx` how it should serve HTTP requests.  | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    Now, change the location section to this snippet: | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       ...; | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8080; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    `proxy_pass` simply tells `nginx` to forward requests to `/` to the | 
    
     | 
     | 
  
    server listening on `http://127.0.0.1:8080`. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 4 -- Reload nginx's Configuration | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    To reload `nginx`'s configuration run:  | 
    
     | 
     | 
  
    `nginx -s reload` on your machine. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    Referesh your browser. _Do you see the output from your `node.js` application?_ | 
    
     | 
     | 
  
    If yes, you are all set. If no, there is a problem with your config. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 5 -- Add /blog and /mail | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    To redirect `/mail` and `/blog`, you simply need to add new entries | 
    
     | 
     | 
  
    the location section in the config file: | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       ...; | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8080; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
         | 
    
     | 
     | 
  
        location /blog { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8181; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
        location /mail { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8282; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 6 -- Reload Your nginx Configuration | 
    
     | 
     | 
  
    Run `nginx -s reload` on your machine. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    Log onto `localhost:$PORT/blog` in your browser. | 
    
     | 
     | 
  
    _Do you see the output from your second `node.js` application?_ | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    Then log onto `localhost:$PORT/mail`. | 
    
     | 
     | 
  
    _Do you see the output from your third `node.js` application?_ | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    If yes & yes, you are all set. If no, there is a problem with your config. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 7 -- Rewriting Requests | 
    
     | 
     | 
  
    Now as you might have noticed in Step 6, nginx sends the same | 
    
     | 
     | 
  
    HTTP request to your `node.js` web apps which results into a 404 error. | 
    
     | 
     | 
  
    Why? Because, your `node.js` web application serves requests from `/` | 
    
     | 
     | 
  
    not from `/blog` and `/mail`. But, `nginx` is sending requests to `/blog` and | 
    
     | 
     | 
  
    `/mail`. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    To fix this issue, we need rewrite the URL so that it matches the URL | 
    
     | 
     | 
  
    you can serve on your `node.js` applications. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    To correctly rewrite URLs change your config file to match the following snippet: | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       ...; | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8080; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
         | 
    
     | 
     | 
  
        location /blog { | 
    
     | 
     | 
  
            rewrite ^/blog(.*) /$1 break; | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8181; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
        location /mail { | 
    
     | 
     | 
  
            rewrite ^/mail(.*) /$1 break; | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8282; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
        ... | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    This rewrite commands are simple regular expressions that transform  | 
    
     | 
     | 
  
    strings like `/blogWHAT_EVER` and `/mailWHAT_EVER` to `/WHAT_EVER` | 
    
     | 
     | 
  
    in the HTTP requests. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 8 -- Reload and Test. | 
    
     | 
     | 
  
    All set? | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Exercise 1 | 
    
     | 
     | 
  
    Configure your nginx to redirect URLs from `/google` to `http://www.google.com` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ### Step 9 (optional) -- Redirecting Based on Host Name | 
    
     | 
     | 
  
    Let say you want to host `example1.com`, `example2.com`, and `example3.com`  | 
    
     | 
     | 
  
    on your machine, respectively to `localhost:8080`, `localhost:8181`, and | 
    
     | 
     | 
  
    `localhost:8282`. | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    **Note:** Since you don't have access to a DNS server, you should | 
    
     | 
     | 
  
    add domain name entries to your `/etc/hosts` (you can't do this on CDF machines): | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    ... | 
    
     | 
     | 
  
    127.0.0.1 example1.com example2.com example3.com | 
    
     | 
     | 
  
    ... | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    To proxy `eaxmple1.com` we can't use the location part of the default server. | 
    
     | 
     | 
  
    Instead we need to add another server section with a `server_name` set  | 
    
     | 
     | 
  
    to our virtual host (e.g., `example1.com`, ...), and then a simple location | 
    
     | 
     | 
  
    section that tells `nginx` how to proxy the requests: | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       80; | 
    
     | 
     | 
  
        server_name  example1.com; | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8080; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       80; | 
    
     | 
     | 
  
        server_name  example2.com; | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8181; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
    server { | 
    
     | 
     | 
  
        listen       80; | 
    
     | 
     | 
  
        server_name  example3.com; | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
        location / { | 
    
     | 
     | 
  
            proxy_pass http://127.0.0.1:8282; | 
    
     | 
     | 
  
        } | 
    
     | 
     | 
  
    } | 
    
     | 
     | 
  
     | 
    
     | 
     | 
  
    ``` | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    Simple, ha?! | 
    
     | 
     | 
  
    
  | 
    
     | 
     | 
  
    
  |