I'm trying to host a Shiny server on the /shiny/ subpath of my website. Using the config below I can reach my demo app via www.example.com/shiny/demo/.

However, when I exclude the last slash from the URI I end up at www.example.com/demo/ instead, which does not exist. I do not know which part of my config leads to this redirect: although I have rewrite_log on I see nothing in error.log. If I remove the rewrite or drop the trailing slash from the proxy_pass everything stops working. The trailing slash in the location directive is not strictly needed (I think?) but I would rather keep it in, removing it seems to make no difference either. I am not sure if I need the proxy_redirect, but removing it does not fix the issue.

Any suggestions on how I can fix my configuration so that the redirect from /shiny/demo to /demo/ goes to /shiny/demo/ instead?

My config, with the relevant location at the bottom:

# Redirect to HTTPS
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;

# Redirect to www subdomain
server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    ssl_certificate /path/to/cert;
    ssl_certificate_key /path/to/key;       

    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

    server_name example.com;
    return 301 https://www.example.com$request_uri;

# Main server
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    root /path/to/root;

    index index.php;
    server_name www.example.com;

    ssl_certificate /path/to/cert;
    ssl_certificate_key /path/to/key;

    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

    location / {
        if ($request_uri ~ ^/(.*)\.html$) {  return 302 /$1;  }
        try_files $uri /$uri $uri.html $uri.php$is_args$query_string;

    location ~ \.php$ {
        if ($request_uri ~ ^/([^?]*)\.php($|\?)) {  return 302 /$1$is_args$query_string;  }
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;

    location ^~ /shiny/ {
        rewrite_log on;
        rewrite ^/shiny/(.*)$ /$1 break;
        proxy_pass http://localhost:1234/;
        proxy_redirect http://localhost:1234/ $scheme://$server_name/shiny/;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
  • Try using curl -I https://www.example.com/shiny/demo and check the value of the Location: response header and check if it matches your proxy_redirect rule. – Richard Smith Jun 12 at 20:10
  • You're right, it is the Shiny server that is redirecting, not Nginx. When I query example.com/shiny/demo I get redirected to https://example.com/shiny/demo, then https://www.example.com/shiny/demo. This gets proxied to the Shiny server, which responds with 301 Location: /demo/. Is there any way to catch this in Nginx? – Pieter Bulls Jun 13 at 6:49
  • Just too late to edit the above... It appears that proxy_redirect / $scheme://$server_name/shiny/ does what I need. Is this safe/valid? – Pieter Bulls Jun 13 at 6:57
  • That should work. I don't think you need the $scheme or $server_name, the documentation suggests that they will be added automatically. So the simplest statement would be proxy_redirect / /shiny/; – Richard Smith Jun 13 at 7:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.