Nginx regex to get uri minus location

nginxregex

I have Nginx running as a reverse proxy to a couple applications. One location directive is running correctly, sending requests to a unix socket file and onwards to its upstream wsgi app. The directive I'm having a problem with is location ~ ^/sub/alarm(.*)$. I have a couple of rewrites which seem to be working, but in case they are colliding with my other intentions, I'll explain my intention with each directive:

  • The first server directive should redirect all http to https. This seems to work fine.
  • The second server directive has one location directive that directs traffic to my wsgi application. This works fine. The other location directive I meant to use to serve static content from /home/myuser/alarm.example.com/ when a GET is received for example.net/sub/alarm. (e.g. example.net/sub/alarm/pretty.css should hand over /home/myuser/alarm.example.com/pretty.css) Instead the wsgi app is loaded.
  • The last server directive should redirect alarm.example.net to example.net/sub/alarm since I don't have a wildcard certificate but wanted but an easy shortcut and encryption. This seems to work fine.

conf:

server {
    listen 80;
    listen [::]:80 ipv6only=on;
    server_name example.com www.example.com;
    rewrite ^/(.*) https://example.com/$1 permanent;
}

server {
        listen 443 ssl;
        listen [::]:443 ipv6only=on ssl;
        charset utf-8;
        client_max_body_size 75M;
        server_name example.com www.example.com;
        ssl_certificate /etc/ssl/certs/example.com.crt;
        ssl_certificate_key /etc/ssl/private/example.com.key;

        location / {
                include uwsgi_params;
                uwsgi_pass unix:///tmp/example.com.sock;
        }

        location ~ ^/sub/alarm(.*)$ {
                alias /home/appusername/alarm.example.com;
                index index.html;
                try_files $1 $1/;
        }
}

server {
        listen 80;
        server_name alarm.example.com;
        rewrite ^ $scheme://example.com/sub/alarm$request_uri permanent;
}

I looked at how to remove location block from $uri in nginx configuration? to try to get the part of my location file after the uri. I think I'm missing something about priorities.

Another attempt was without regex:

location /sub/alarm/ {
        alias /home/appusername/alarm.example.com;
        index index.html;
        try_files $uri $uri/index.html =404;
}

In the above case I was able to load index.html when going to alarm.example.com (which correctly redirected to https://example.com/sub/alarm/), but all the resources were throwing a 404.

Finally I tried to combine both attempts, but it seems I can't put the tilde inside the location block ('unknown directive' when reloading Nginx):

location /sub/alarm/ {
        ~ ^/sub/alarm(.)$
        try_files /home/appusername/alarm.example.com$1 /home/appusername/alarm.example.com$1/;
}

Additional Notes

  • The dynamic app on example.com is totally unrelated to the "alarm" app which is static. It's included only because it's getting served instead of the alarm app when I attempt the regex.
  • I've always avoided learning anything about regex (probably unwise, but I never really needed it over the last 7 years till today) and am paying the price now that I'm configuring Nginx. I used Regex 101 to get my regex string of ^\/sub\/alarm(.*)$. It seemed to indicate that I needed to use escape slashes, but Nginx doesn't seem to show that in examples. Please let me know if there's another concept I need to study. I officially end my regex avoidance stance starting today.
  • If the syntax was valid enough for Nginx to reload, my error was 2015/10/12 20:25:57 [notice] 30500#0: signal process started in all attempts.

Best Answer

So the user (eh... me) missed something that should have been a glaring clue:

In the above case I was able to load index.html when going to alarm.example.com (which correctly redirected to https://example.com/sub/alarm/), but all the resources were throwing a 404.

Even though that example still wasn't correct, I should have checked file permissions on the resource files. Nginx is running as www-data and in the group for the index.html file but needed to be in the group for all files. The file owner is the appusername user.

I've since added another app (called 'beer') which is routed like alarm. I've now learned the basics of regex and was able to do this in one location block:

server {
    listen 80;
    listen [::]:80 ipv6only=on;
    server_name example.com www.example.com;
    rewrite ^/(.*) https://example.com/$1 permanent;
}

server {
        listen 443 ssl;
        listen [::]:443 ipv6only=on ssl;
        charset utf-8;
        client_max_body_size 75M;
        server_name example.com www.example.com;
        ssl_certificate /etc/ssl/certs/example.com.crt;
        ssl_certificate_key /etc/ssl/private/example.com.key;
        error_log /var/log/nginx/error.log warn;

        location ~ ^/sub/(alarm|beer)(.*)$ {
                alias /home/appusername/$1.example.com/;
                #index  index.html index.htm;
                try_files $2 $2/ =404;
        }

        location / {
                include uwsgi_params;
                uwsgi_pass unix:///tmp/example.com.sock;
        }
}

server {
        listen 80;
        server_name alarm.example.com;
        rewrite ^ $scheme://example.com/sub/alarm$request_uri permanent;
}

Don't mind the switch in order for the location blocks. That is only coincidence of typing and retyping.