11

Hello so I have two platforms where one operates as a subdirectory. I would like to be able to have an access and error log for each application; however it is not working as I intended :(

Here is what I have:

server {
    listen 80 default;
    listen [::]:80;

    root /var/www/html/app1;
    index index.php;

    server_name localhost;

    access_log /var/log/nginx/app1.access.log;
    error_log /var/log/nginx/app1.error.log;    

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
    location ~ /\.(?!well-known).* {
            deny all;
            access_log off;
            log_not_found off;
    }
    location ~*  \.(woff|jpg|jpeg|png|gif|ico|css|js)$ {
        access_log off;
        log_not_found off;
        expires 365d;
    }

    location / {
        try_files $uri $uri/ /index.php?$is_args$args;
    }   


    location /app2 {

        try_files $uri $uri/ /app2/index.php$is_args$args;

        access_log /var/log/nginx/app2.access.log;
        error_log  /var/log/nginx/app2.error.log;
    }

    # SECURITY : Deny all attempts to access PHP Files in the uploads directory
    location ~* /(?:uploads|files)/.*\.php$ {
            deny all;
    }

    # PHP : pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;    
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Yoast SEO Sitemaps
    location ~ ([^/]*)sitemap-rewrite-disabled(.*).x(m|s)l$ {
            ## this redirects sitemap.xml to /sitemap_index.xml
        rewrite ^/sitemap.xml$ /sitemap_index.xml permanent;
            ## this makes the XML sitemaps work
            rewrite ^/([a-z]+)?-?sitemap.xsl$ /index.php?xsl=$1 last;
        rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
        rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;
            ## The following lines are optional for the premium extensions
        ## News SEO
            rewrite ^/news-sitemap.xml$ /index.php?sitemap=wpseo_news last;
        ## Local SEO
        rewrite ^/locations.kml$ /index.php?sitemap=wpseo_local_kml last;
        rewrite ^/geo-sitemap.xml$ /index.php?sitemap=wpseo_local last;
        ## Video SEO
        rewrite ^/video-sitemap.xsl$ /index.php?xsl=video last;
    }
}

Only visits to the app2 homepage get logged in the app2 logs while further into the site like /app2/help will appear in the app1 logs.

Examples:

/help == app1.access.log && app1.error.log OK

/app2 == app2.access.log && app2.error.log OK

/app2/help == app1.access.log && app1.error.log *(want to be in app2 logs) NOT OK

0

4 Answers 4

8
+50

This is happening because the location that ultimately ends up handling your requests is location ~ \.php$, which inherits its log configuration from the server context. Assuming that the yoast seo sitemap belongs to app1, you'll want a config something like this:

# Use an upstream to future changes easier
upstream _php {
    server unix:/var/run/php/php7.0-fpm.sock;
}

server {
    listen 80 default;
    listen [::]:80;

    root /var/www/html/app1;
    index index.php;

    server_name localhost;

    access_log /var/log/nginx/app1.access.log;
    error_log /var/log/nginx/app1.error.log;    

    # Put php directives in the server context so they can be inherited by all locations
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }

    # Locations that aren't logged can be left outside and shared
    location ~ /\.(?!well-known) {
        deny all;
        access_log off;
        log_not_found off;
    }

    location ~* \.(woff|jpg|jpeg|png|gif|ico|css|js)$ {
        access_log off;
        log_not_found off;
        expires 365d;
    }

    # Everything that logs to app1 should go in here
    location / {
        try_files $uri $uri/ /index.php?$is_args$args;

        # SECURITY : Deny all attempts to access PHP Files in the uploads directory
        location ~* /(?:uploads|files)/.*\.php$ {
            deny all;
        }

        # PHP : pass the PHP scripts to FastCGI server defined in upstream _php
        location ~ \.php$ {
            fastcgi_pass _php;
        }

        # Yoast SEO Sitemaps
        location ~ ([^/]*)sitemap-rewrite-disabled(.*).x(m|s)l$ {
                ## this redirects sitemap.xml to /sitemap_index.xml
            rewrite ^/sitemap.xml$ /sitemap_index.xml permanent;
                ## this makes the XML sitemaps work
                rewrite ^/([a-z]+)?-?sitemap.xsl$ /index.php?xsl=$1 last;
            rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
            rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;
                ## The following lines are optional for the premium extensions
            ## News SEO
                rewrite ^/news-sitemap.xml$ /index.php?sitemap=wpseo_news last;
            ## Local SEO
            rewrite ^/locations.kml$ /index.php?sitemap=wpseo_local_kml last;
            rewrite ^/geo-sitemap.xml$ /index.php?sitemap=wpseo_local last;
            ## Video SEO
            rewrite ^/video-sitemap.xsl$ /index.php?xsl=video last;
        }
    }   

    # Everything that logs to app2 should go in here
    location /app2 {
        try_files $uri $uri/ /app2/index.php$is_args$args;

        access_log /var/log/nginx/app2.access.log;
        error_log  /var/log/nginx/app2.error.log;

        # SECURITY : Deny all attempts to access PHP Files in the uploads directory
        location ~* /(?:uploads|files)/.*\.php$ {
            deny all;
        }

        # PHP : pass the PHP scripts to FastCGI server defined in upstream _php
        location ~ \.php$ {
            fastcgi_pass _php;
        }
    }
}

Moving the fastcgi params into the server and using an upstream for the php server means it's not a lot to duplicate.

1
  • Yep that was it. I figured it out myself yesterday but your solution is cleaner than mine so double kudos. Thank you
    – Ray
    May 18, 2018 at 21:00
2

You can try the conditional logging with "if". Setup a map for each location and add "if" in the log statement.

map $uri $app1 {
    ~^[app1] 1;
    default 0;
}
map $uri $app2 {
    ~^[app2]  1;
    default 0;
}

access_log /path/to/access-app1.log combined if=$app1;
access_log /path/to/access-app2.log combined if=$app2;

Please note - above statement is written for reference purpose not tested, there might be some syntax changes required.

1

According to NGINX documentation regarding location:

[...] To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

So, if any of the location blocks with regex below or above the location /app2 catches the URL, it will be sent to the default server log (or to no log file, according to some of your options).

The priority for sorting works like this:

  • (none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match.
  • =: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given.
  • ~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match.
  • ~*: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match.
  • ^~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place.

I'm removing some of the configuration for clarity.

Maybe you could try giving app2 priority, regex with ^~ and see what happens:

 server {
     listen 80 default;
     listen [::]:80;

     root /var/www/html/app1;
     index index.php;

     server_name localhost;

     access_log /var/log/nginx/app1.access.log;
     error_log /var/log/nginx/app1.error.log;

     location / {
         try_files $uri $uri/ /index.php?$is_args$args;
     }

     location ^~ /app2 {

         try_files $uri $uri/ /app2/index.php$is_args$args;

         access_log /var/log/nginx/app2.access.log;
         error_log  /var/log/nginx/app2.error.log;
     }
 }

This should make sure to execute the best matching non-regular expression, and leave the regex blocks as second and shouldn't need to be duplicated to catch the other locations, as the are inherited.

0

The config looks correct. nginx does a longest match on the location if you don't use = or ~, so anything that begins with /app2/ including /app2/helper will match the second location and take priority over location /

I cannot reproduce your problem using the very same configuration that you posted. My guess is that you didn't restart nginx. A reload might not be enough.

4
  • I have restarted nginx and even stopped and started it to no avail :( Here is the version I am using: nginx version: nginx/1.10.3 (Ubuntu)
    – Ray
    May 8, 2018 at 18:18
  • same ver. here. Are you sure that you provided the exact config that you are using in production? Are you accessing the site as localhost/app2/helper ? May 8, 2018 at 22:13
  • I have updated my question with the whole config. No it is not EXACTLY the same the server_name is not localhost and app1 and app2 are made up endpoints for obfuscation purposes. Everything else is the same @luca-gibelli
    – Ray
    May 9, 2018 at 18:38
  • the php part was missing too and it was reason of the problem May 21, 2018 at 10:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .