Nginx subdirectory configuration

Nginx subdirectory configuration

by Yoro Loro -
Number of replies: 9
I am trying to setup moodle 3.4 (git cloned), I used apache2 to install it to a subdirectory n my site. But apache2 consumes alot of memory that I do not have, so I am switching my sites to use nginx but I do not know the proper configuration of moodle powere by nginx in a subdirectory install.



I need to know what request methods moodle uses so I can block other non essential request methods and I also need the content security policy. Also, can someone explain how the slash rule work my moodle site is on a subdirectory.
I installed moodle using apache but I migrated to nginx.

Here is my configuration, please pay attention to the TODO
moodle.conf in sites-enabled


server {

 #################################################
 # Stock useful config options, but ignore them :)
 #################################################
 include /etc/nginx/mime.types;

    # mozilla server config https://mozilla.github.io/server-side-tls/ssl-config-generator/
    listen 443 ssl http2;
    ssl on;
    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /etc/letsencrypt/live/xxxx.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/xxxx.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/nginx/dhparam.pem;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/xxxxxxcom/chain.pem;

    #OWASP SERVER HARDENING
    add_header X-XSS-Protection "1; mode=block";

    #TODO WHAT REQUEST METHODS MOODLE USES?
    if ($request_method !~ ^(GET|HEAD|POST)$ )
    {
         return 405;
    }
    
    #OWASP SERVER HARDENING
    #TODO WHAT CONTENT SECURITY POLICY MOODLE NEEDS?
    add_header Content-Security-Policy "default-src 'self';";
    add_header X-Frame-Options "sameorigin";
    add_header Referrer-Policy "strict-origin";

 # prevent attacks (someone uploading a .txt file that the browser
 # interprets as an HTML file, etc.)
 add_header X-Content-Type-Options nosniff;

 server_name zxxxx.com;
 access_log /var/log/nginx/access.log;
 error_log /var/log/nginx/error.log;
 #CUSTOM ERROR PAGE
 error_page 500 502 503 504 404 403 501 401 400 /301.html;

  root /var/USB/www;
  index index.php;

# DENY RULES

## Disable .htaccess and other hidden files
location ~ /\. {
    return 404;
}

location ~ /(robots.txt) {
    allow all;
}

location ~ \.(log|ini|md|MD|sql|lock|json|txt|TXT|dist|yml)$ {
    return 404;
}

#TODO IS THIS RIGHT?
#MY MOODLE INSTALL IS ON THE SUBDIRECTORY: http://mysite.com/moodle/ not http://mysite.com
#EVEN IF I REMOVE THE BELOW CONFIG IT WORKS
location ~ /moodle/[^/]\.php(/|$) {
    fastcgi_split_path_info  ^(.+\.php)(/.+)$;
    fastcgi_index            index.php;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    include                  fastcgi_params;
    fastcgi_param   PATH_INFO       $fastcgi_path_info;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

location /dataroot/ {
    internal;
    alias /var/USB/moodledata/; # ensure the path ends with /
}

  #PHP
  location ~ \.php {
    include snippets/fastcgi-php.conf;

    # This should be the same value as in your (optional) /etc/php5/fpm/pool.d/$server.conf
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}

#end
}



Average of ratings: -
In reply to Yoro Loro

Re: Nginx subdirectory configuration

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Yoro,
first you do not need dataroot aliasing if you're not using xsendfile: are you using it in your config.php file?

Regarding w/ your TODOs, here are my replies:

  1. WHAT REQUEST METHODS MOODLE USES? => Correct: GET|HEAD|POST
  2. WHAT CONTENT SECURITY POLICY MOODLE NEEDS? => None, you can create it as per your own policy, even using https://moodle.org/plugins/local_csp
  3. IS THIS RIGHT? MY MOODLE INSTALL IS ON THE SUBDIRECTORY: http://mysite.com/moodle/ not http://mysite.com EVEN IF I REMOVE THE BELOW CONFIG IT WORKS => Correct: it looks like the standard configuration as per https://docs.moodle.org/34/en/Nginx#Nginx; it is required since you need to properly activate the support for PATH_INFO for first level PHP files since, at that level, there are those files used to serve the Moodle generated files (e.g. content stored in Moodle or theme related files via e.g. pluginfile.php). If you'll remove it the PHP handler will be still exposed few lines above but the PATH_INFO as per a "soft" requirement i.e. you can still disable Moodle slash argument support to let it work, not recommended!

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Nginx subdirectory configuration

by Yoro Loro -
it is in this part: (it assumes that you are only running moodle in the root host not in subdirectory)
location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info  ^(.+\.php)(/.+)$;
    fastcgi_index            index.php;
    fastcgi_pass             127.0.0.1:9000 (or your php-fpm socket);
    include                  fastcgi_params;
    fastcgi_param   PATH_INFO       $fastcgi_path_info;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
that I do not know how to put the moodle subdirectory in it. I tried the above by adding the moodle in the location but it does not do anything no difference in accessing the site with or without that config.



In reply to Yoro Loro

Re: Nginx subdirectory configuration

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Yoro,
yes I mean that part and I second your slight change on your location{ ... }: if you look at the URLs of your site (via <F12> in the browser) how do they look like?

See e.g. some URLs coming from the theme of moodle.org:

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Nginx subdirectory configuration

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Yoro,
could you share here your snippets/fastcgi-php.conf ?
Maybe the PATH_INFO configuration is already there and this could explain why "your configuration" still works w/o the "recommended" Moodle configuration.

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Nginx subdirectory configuration

by Yoro Loro -
hi, here is the /etc/nginx/snippets/fastcgi-php.conf



i have not tested in viewing moodle with browser F12 but will try later

regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;

# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;

# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

fastcgi_index index.php;
include fastcgi.conf;

In reply to Yoro Loro

Re: Nginx subdirectory configuration

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Yoro,
no need to check from your browser since that "snippet" takes care of properly setting PATH_INFO and that's the reason why the "Moodle location" is not necessary but for the line:

fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;

which looks like already properly set from your real life evidence by nginx.

Guessing that fastcgi.conf contains just the coordinates of the engine, worth sharing it here too.

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Nginx subdirectory configuration

by Yoro Loro -
Here is the /etc/nginx/fastcgi.conf

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;

Honestly, I do not understand the nginx configuration. I always used apache but now I need to save memory so I used nginx.
I used the xsendfile I just forgot to include it in my posts. So I need the right configuration for a site with other subsites.
I noticed there are dot (hidden) files in the moodle directory, which do I need to deny access in them
I am currently using this:

server{ 
# ... secure headers/options ...
#excerpt from the above config

root /mnt/USB/www;
index index.php index.html;

#location of moodle data
location /dataroot/ {
internal;
alias /mnt/USB/moodledata/; # ensure the path ends with /
}

#PHP
location ~ \.php {
include snippets/fastcgi-php.conf;

# This should be the same value as in your (optional) /etc/php5/fpm/pool.d/$server.conf
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

}

#end
}

or should I still use this but I do not know if it can cause my other site to fail or behave erratically:
server{ 
# ... secure headers/options ...
#excerpt from the above config

root /mnt/USB/www;
index index.php index.html;

#it is not set to location /moodle? should I
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
# fastcgi_pass 127.0.0.1:9000 (or your php-fpm socket); IDONOT USE THIS
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}


location /dataroot/ {
internal;
alias /mnt/MEDIA/moodledata/; # ensure the path ends with /
}

#end
}
In reply to Yoro Loro

Re: Nginx subdirectory configuration

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Yoro,
based on the content of your /etc/nginx/fastcgi.conf, just remove:

#TODO IS THIS RIGHT?
#MY MOODLE INSTALL IS ON THE SUBDIRECTORY: http://mysite.com/moodle/ not http://mysite.com
#EVEN IF I REMOVE THE BELOW CONFIG IT WORKS
location ~ /moodle/[^/]\.php(/|$) {
    fastcgi_split_path_info  ^(.+\.php)(/.+)$;
    fastcgi_index            index.php;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    include                  fastcgi_params;
    fastcgi_param   PATH_INFO       $fastcgi_path_info;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

from the conf on your first post and you'll be fine i.e. stick with the first conf of your last post, validated both from real life usage and theory.

Dot files should be hidden i.e. sue something like https://serverfault.com/questions/755662/nginx-disable-htaccess-and-hidden-files-but-allow-well-known-directory to deny the dot files but the one required by Let's Encrypt.

About X-Sendfile: do you mean that you've actually changed the Moodle config.php file according with https://docs.moodle.org/34/en/Nginx#XSendfile_aka_X-Accel-Redirect?

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: Nginx subdirectory configuration

by Yoro Loro -

Yes I used xsendfile and changed config as per in the instructions.

So here is my final server config: I did not touch fastcgi.conf nor snippets, I also did not uncheck the slash arguments* IIRC in the moodle site admin config

I will update later if I encounter problems. Thank You


server {


#################################################

# Stock useful config options, but ignore them smile

#################################################

include /etc/nginx/mime.types;


# mozilla server config https://mozilla.github.io/server-side-tls/ssl-config-generator/

listen 443 ssl http2;

ssl on;

# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate

ssl_certificate /etc/letsencrypt/live/xxxx.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/xxxx.com/privkey.pem;

ssl_session_timeout 1d;

ssl_session_cache shared:SSL:50m;

ssl_session_tickets off;


# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits

ssl_dhparam /etc/nginx/dhparam.pem;


# intermediate configuration. tweak to your needs.

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';

ssl_prefer_server_ciphers on;


# OCSP Stapling ---

# fetch OCSP records from URL in ssl_certificate and cache them

ssl_stapling on;

ssl_stapling_verify on;


## verify chain of trust of OCSP response using Root CA and Intermediate certs

ssl_trusted_certificate /etc/letsencrypt/live/xxxxxxcom/chain.pem;


#OWASP SERVER HARDENING

add_header X-XSS-Protection "1; mode=block";


#TODO WHAT REQUEST METHODS MOODLE USES?

if ($request_method !~ ^(GET|HEAD|POST)$ )

{

return 405;

}



#OWASP SERVER HARDENING

#TODO WHAT CONTENT SECURITY POLICY MOODLE NEEDS?

add_header Content-Security-Policy "default-src 'self';";

add_header X-Frame-Options "sameorigin";

add_header Referrer-Policy "strict-origin";


# prevent attacks (someone uploading a .txt file that the browser

# interprets as an HTML file, etc.)

add_header X-Content-Type-Options nosniff;


server_name zxxxx.com;

access_log /var/log/nginx/access.log;

error_log /var/log/nginx/error.log;

#CUSTOM ERROR PAGE

error_page 500 502 503 504 404 403 501 401 400 /301.html;


root /var/USB/www;

index index.php;


# DENY RULES


## Disable .htaccess and other hidden files

location ~ /\. {

return 404;

}


location ~ /(robots.txt) {

allow all;

}


location ~ \.(log|ini|md|MD|sql|lock|json|txt|TXT|dist|yml)$ {

return 404;

}




location /dataroot/ {

internal;

alias /var/USB/moodledata/; # ensure the path ends with /

}


#PHP

location ~ \.php {

include snippets/fastcgi-php.conf;


# This should be the same value as in your (optional) /etc/php5/fpm/pool.d/$server.conf

fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

}


#end

}