How to handle relative urls correctly with a nginx reverse proxy

51,754

The problem is basically that using a proxy_pass directive won't rewrite HTML code and therefor relative URL's to for instance a img src="/assets/image.png" won't magically change to img src="/bbb/assets/image.png".

I wrote about potential strategies to address that in Apache httpd here and similar solutions are possible for nginx as well:

  • If you have control over example.com and the how the application/content is deployed there, deploy in the same base URI you want to use on example.net for the reverse proxy
    --> deploy your code in example.com/bbb and then your proxy_pass will become quite an easy as /assets/image.png will have been moved to /bbb/assets/image.png:

    location /bbb/ {
         proxy_pass http://example.com/bbb/; 
    
  • If you have control over example.com and the how the application/content is deployed:
    change to relative paths, i.e. rather than img src="/assets/image.png"
    refer to img src="./assets/image.png" from a page example.com/index.html
    and to img src="../../assets/image.png"from a page example.com/some/path/index.html

  • Maybe you're lucky and example.com only uses a few URI paths in the root and non of those are used by example.net, then simply reverse proxy every necessary subdirectory:

    location /bbb/ {
         proxy_pass http://example.com/; 
    }
    location /assets/ {
         proxy_pass http://example.com/assets/; 
    }
    location /styles/ {
         proxy_pass http://example.com/styles/; 
    
  • give up using a example.com as subdirectory on example.net and instead host it on a subdomain of example.net:

    server { 
      server_name bbb.example.net 
      location / {
         proxy_pass http://example.com/; 
      }
    }
    
  • rewrite the (HTML) content by enabling the nginx ngx_http_sub_module. That will also allow you to rewrite absolute URL's with something similar to:

    location /bbb/ {
         sub_filter 'src="/assets/'  'src="/bbb/assets/';
         sub_filter 'src="http://example.com/js/' 'src="http://www.example.net/bbb/js/' ;
         sub_filter_once off;
         proxy_pass http://example.com/; 
    }
    
Share:
51,754

Related videos on Youtube

a.barbieri
Author by

a.barbieri

Hello!

Updated on September 18, 2022

Comments

  • a.barbieri
    a.barbieri almost 2 years

    Sure I'm not the first one that tried to serve a domain example.com from a example.net/bbb, but I haven't found a solution yet.

    My NGINX configuration follows the guidelines and looks something like this:

    server {
        listen 80;
        server_name example.net;
        root /path/to/aaa;
    
        location /bbb/ {
            proxy_pass http://example.com/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    
        location / {
            try_files $uri $uri/ /index.html;
        }
        location ~ \.(svg|ttf|js|css|svgz|eot|otf|woff|jpg|jpeg|gif|png|ico)$ {
            access_log off;
            log_not_found off;
            expires max;
        }
    }
    

    I can manage to render the root of example.com in example.net/bbb but:

    ISSUE 1

    example.net/bbb/some/path doesn't work as expected and the index.html of example.net is rendered.

    ISSUE 2

    Any asset in example.com/assets gives 404 because the browser look for example.net/assets. Be great if I could solve this without placing absolute paths everywhere.

  • a.barbieri
    a.barbieri almost 6 years
    I can definitely do the first option. The last one is pretty extreme but it's good to know there's such an alternative.
  • Sammy
    Sammy over 4 years
    Excellent explanation of the implementation options. I've been looking for a breakdown like this for quite some time, happy I finally found it. Thank you.