43

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.

HBruijn
  • 84,206
  • 24
  • 145
  • 224

5 Answers5

66

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

Late addition

  • Sometimes developers provide special application settings specifically for deployments where the application is behind a reverse proxy or behind a CDN. The application can then be configured to generate self referential URL's, with the protocol, the site name and URI path that users are/should be using, rather then the hostname, the protocol and/or the URI the application detects. Expect terms like external URL, site URL. Then you don't need to solve anything in nginx.
HBruijn
  • 84,206
  • 24
  • 145
  • 224
1

I found the reason why the index page cannot correctly jump to sub-folder like \bbb is this line in html file: <base href="/">, which means it will throw off any existing folder whenever jump to a new path.

George Y
  • 618
  • 3
  • 11
  • 20
0

if you want to subdir's html file for default index.html. for example, copy /main/mainView.html to /index.html and use base tag in index.html to set relative location's base path.

*I think adjusting client page's relative location's base path can be modified by not server-side but client-side(browser). because the page(client-side asset) has no way to know its real location in server-side.

0

I had issues like you , If i have two container , each of them load a different frontend app , you should change a base root url for each your project in html for example :

<base target="_blank" href="http://localhost:8081/react-app/" />

this is in another container , but main project is on 80 , so it can find style files and etc . and for change a base route for child route i found sth for react router as name basename that can set

0

Since the homepage already redirects you to the path "/admin/", the correct approach would be to check the path and issue a "return 302" to adjust the "location" as it appears in the original URL. See the examples below.

Nginx version

Docker: nginx:1.25-alpine3.18
Nginx: 1.25

Original URL:

http://192.168.29.2:8088/admin/

Reverse proxy:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name ~^(dns).youdomain.com;
client_max_body_size 50M;
include ssl_config.config;

location = / {
    return 302 https://$host/admin/;
}

location /admin/ {
    proxy_pass http://192.168.29.2:8088/admin/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

}

ssl_config.config

    # SSL configuration
    ssl_certificate         /etc/nginx/certs/certificate.crt;
    ssl_certificate_key     /etc/nginx/certs/certificate.key;
#ssl_protocols TLSv1.3 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-CHACHA20-POLY1305;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver_timeout 5s;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection &quot;1; mode=block&quot;;

ssl_dhparam /etc/nginx/certs/dhparam.pem;

# Your server DNS here
resolver 192.168.29.2;