403 Forbidden + Nginx + Virtual Host configuartion + NodeJS - node.js

I am getting 403 Forbidden on Server virtual host configure using Nginx for NodeJS application.
Configuration file code:
server {
listen 443 default_server;
listen [::]:443 default_server;
ssl on;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /mnt/var/www/example.com/app/public/;
index index.html index.htm index.php;
server_name example.com www.example.com;
access_log /var/log/nginx/dygnostica_access.log;
error_log /var/log/nginx/dygnostica_error.log;
location / {
include /etc/nginx/proxy_params
try_files $uri $uri/ =404;
}
}
server {
listen 0.0.0.0:80;
server_name example.com www.example.com;
rewrite ^ https://$host$request_uri? permanent;
}
I have setup all configuration based on this article.
Need help to resolve 403. Thanks in advance.
EDIT:
Error log says:
directory index of "/mnt/var/www/example.com/app/public/" is forbidden.

I think you have wrong configuration for virtual host. Here is my nginx config file. I have standard PHP application (https) on main domain and node app on subdomain (running on port 3000):
#// virtual host for node app:
server {
server_name node.domain.cz;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
#// host (for PHP app)
server {
listen 80;
server_name domain.cz www.domain.cz;
root /var/www/domain.cz/www;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
listen 443 ssl; # managed by Certbot
# ssl_certificate ...
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
}

Related

Nginx Redirect To Https Except One or More Folders

I would like to serve some of my website static assets like .txt, .csv, images and other document types as non https. But my current configuration always redirects to https.
server {
listen 80;
listen [::]:80;
root /var/www/public;
index index.php index.html index.htm;
server_name example.com www.example.com;
location / {
return 301 https://$host$request_uri;
}
location /static/ {
root /var/www/public/static;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
root /var/www/public;
index index.php index.html index.htm;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
}
}
I have been reading similar questions here in SO:
Nginx: Redirect all to https except one laravel url = too many redirects
nginx: redirect everything from http to https, except one url-pattern
But nothing works for me and worst returns too many redirect.

Nginx routing not working when refresh page or when I go directly to the page

I'm running Docker Containers with a Vue.js front and a Node.js+Express.js backend and managing the routes using Nginx.
When I access the route https://equilibrista.app/ and click the link inside the page to go to https://equilibrista.app/exams it works fine, but I got an error when I directly goes to this page (and a Express error shows up Cannot GET /exams).
Why is this happening? It looks like an Nginx redirect error, but I couldn't find anything wrong on nginx.conf
server {
listen 80;
listen [::]:80;
server_name equilibrista.app www.equilibrista.app;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name equilibrista.app www.equilibrista.app;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/equilibrista.app/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/equilibrista.app/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location /api/ {
proxy_pass http://api:3000/;
proxy_redirect off;
}
location / {
proxy_pass http://front:8888;
}
}
The way we got it to work with a Vue app was following.
1) First you have a location that capture all the physical files and paths that exists.
2) Secondly you redirect any other request to the main application file, for Vue it is index.html.
So your location configuration should look like this:
location /api/ {
proxy_pass http://api:3000/;
}
location ~* \/(index\.html|favicon\.ico|styles\.css|styles\.min\.css|css\/.*|js\/.*|images\/.*) {
proxy_pass http://front:8888;
}
location / {
rewrite / /index.html;
proxy_pass http://front:8888;
}
(updated to match question)
we have the static files on the nginx server, but it should work the same way with proxy_pass.

Exclude API Route From Nginx HTTP Basic Authentication

I'm trying to exclude the API route "https://example.com/api/" from the Nginx HTTP Basic Authentication.
Here is my Nginx Conf:
server {
listen 80;
listen [::]:80;
server_name example.com;
return 302 https://$server_name$request_uri;
}
server {
# SSL configuration
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/nginx/ssl/cert.crt;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_client_certificate /etc/nginx/ssl/cloudflare.crt;
ssl_verify_client on;
server_name example.com;
root /var/www/mysite;
index app.php index.php;
location / {
try_files $uri $uri/ /app.php$is_args$args;
# Restricting Access
auth_basic 'Administrator Area';
auth_basic_user_file /etc/apache2/.htpasswd;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
# Restriction off for api
location ^~ /api/ {
auth_basic off;
allow all;
}
}
But when I try to hit "https://example.com/api/" on the browser, it's still asking for basic authentication. Usually, without basic authentication, it should provide a JSON response on the browser.
Does anyone know how to solve this issue? Any kind of help would be greatly appreciated. Thanks.

(Nginx) Non-HTTP/Non-WWW to HTTPS/WWW Leads to PHP (Without Extension) File Being Downloaded

I have been browsing various threads for many hours (not exaggerated), but have been unable to find a solution combination that allows me to forward a non-www and http to a www and https while still being able to view php files without the extension. As follows is my nginx configuration file; any and all help IS appreciated!
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
server {
listen 80;
server_name domain.com;
rewrite ^(.*) http://www.domain.com$1 permanent;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name www.domain.com;
root /usr/share/nginx/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ #extensionless-php;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
# Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests
#location /RequestDenied {
# proxy_pass http://127.0.0.1:8080;
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# root html;
# index index.html index.htm;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
# HTTPS server
server {
listen 443;
server_name www.domain.com;
root html;
index index.html index.htm index.php;
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
location / {
try_files $uri $uri/ =404;
}
}
P.S. Generic code (i.e. domain.com) was provided in order for others to use this solution if so desired!
Edit: I have solved my own question! See my solution below. :)
I have found the solution to my own question! Hopefully this can be of use to some people out there. Basically, the modifications in the NGINX configuration file forward http://domain.com to http://www.domain.com and then forward http://www.domain.com to https://www.domain.com, all without using .php extensions.
That is, I can access a PHP file called "phpinfo," at https://www.domain.com/phpinfo.php by just visiting domain.com/phpinfo (or the full URL, https://www.domain.com/phpinfo <-- without the php extension). This may seem rather trivial to some users, but it is useful to a beginner like myself.
I had to make a small addition to the code from my question, whose updated form can be found below. Underneath server { ... } for HTTPS, I had to duplicate the location / { ... }, location ~ .php$ { ... }, and location #extensionless-php { ... } from the normal HTTP server { ... }.
As follows is the updated code for easy viewing! I hope this has proven useful.
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
server {
listen 80;
server_name domain.com;
rewrite ^(.*) https://www.domain.com$1 permanent;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name www.domain.com;
rewrite ^(.*) https://www.domain.com$1 permanent;
root /usr/share/nginx/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ #extensionless-php;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
# Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests
#location /RequestDenied {
# proxy_pass http://127.0.0.1:8080;
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# root html;
# index index.html index.htm;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
# HTTPS server
server {
listen 443;
server_name www.domain.com;
root html;
index index.html index.htm index.php;
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
location / {
# NOTE: THIS REQUIRED AN EDIT.
try_files $uri $uri/ #extensionless-php;
}
# NOTE: THE FOLLOWING CODE IS A MERE DUPLICATE FROM THE HTTP SERVER ABOVE!
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
}
ok well here's a little simplification to your config, ultimately you want to go to the https+www domain, the double redirection is a waste. so redirect to that directly
server {
# handles both www and non www to http
listen 80;
server_name www.example.com example.com;
return 301 https://www.example.com$request_uri$is_args$query_string;
}
server {
# handles non www to https
listen 443 ssl;
# add ssl settings to avoid certificate error
server_name example.com;
return 301 https://www.example.com$request_uri$is_args$query_string;
}
server {
listen 443 ssl;
server_name www.example.com;
# ssl settings
location / {
try_files $uri $uri/ #extensionless;
}
location #extensionless {
rewrite ^ $1.php last;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
I believe this small php block is sufficient, if it doesn't work you can add back the remaining rules from your current config.

Nginx: redirect non-www to www on https

Nginx isn't working to redirect non-www to www if I'm on https:
https://domain.com to https://www.domain.com
My curent setup in .conf is:
server {
listen 80;
server_name www.domain.com domain.com;
return 301 https://www.domain.com$request_uri;
}
server {
listen 443;
server_name domain.com;
return 301 https://www.domain.com$request_uri;
}
server {
listen IP_ADDRESS:443 ssl;
server_name www.domain.com;
...
}
http://domain.com to https://www.domain.com and http://www.domain to https://www.domain.com works, but non-www to www on https isn't working.
If I added the IP_ADDRESS on the second server block, I get an error in Chrome (SSL error) and both (www and non-www) stop working.
UPDATE:
Thanks to Steffen (below answer), I updated the self-signed certificate to be *.domain.com and not domain.com.
The .conf file was updated under this format:
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
server {
listen 80;
server_name www.domain.com domain.com;
return 301 https://www.domain.com$request_uri;
}
server {
listen 443 ssl;
server_name domain.com;
return 301 https://www.domain.com$request_uri;
}
server {
listen 443 ssl;
server_name www.domain.com;
...
}
I had similar kind of scenario and this is how I solved the redirection problem
https://example.com -----> https://www.example.com
server {
listen 443;
server_name example.com;
if ($host = example.com) {
rewrite ^(.*) https://www.example.com:443$request_uri? permanent;
}
}
Hope this helps!
Using if condition in nginx
Directive if has problems when used in location context, in some cases it doesn't do what you expect but something completely different instead. In some cases it even segfaults. It's generally a good idea to avoid it if possible. The only 100% safe things which may be done inside if in location context are:
return ...; rewrite ... last;
In 2nd server block (one starting with "listen 443;") you must add all SSL-related directives that are in the SSL server group (last group). This is my example.conf:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
return 301 https://www.$server_name$request_uri;
# SSL
ssl on;
ssl_certificate /var/www/example.com/cert/bundle.cer;
ssl_certificate_key /var/www/example.com/cert/example.com.key;
# Enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Intermediate cypersuite as recommended by Mozilla
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
# Add HSTS (HTTPStrictTransportSecurity)
add_header Strict-Transport-Security "max-age=31536000";
}
server {
listen 443 ssl;
server_name www.example.com;
root /var/www/example.com/public;
index index.html index.htm index.php;
client_max_body_size 32m;
access_log /var/www/example.com/access.log;
error_log /var/www/example.com/error.log;
# SSL
ssl on;
ssl_certificate /var/www/example.com/cert/bundle.cer;
ssl_certificate_key /var/www/example.com/cert/example.com.key;
# Enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Intermediate cypersuite as recommended by Mozilla
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
# Add HSTS (HTTPStrictTransportSecurity)
add_header Strict-Transport-Security "max-age=31536000";
# Directives to send expires headers and turn off 404 error logging.
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
#expires max;
log_not_found off;
access_log off;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
## Disable viewing .htaccess & .htpassword
location ~ /\.ht {
deny all;
}
location ^~ /admin/ {
auth_basic "Restricted";
auth_basic_user_file /var/www/example.com/.htpasswd;
try_files $uri $uri/ /index.php$is_args$args;
location ~ \.php$ {
include /etc/nginx/php-inside.conf;
}
}
include /etc/nginx/php.conf;
}
This is probably because you don't have a certificate for domain.com, but only for www.domain.com or *.domain.com. See Nginx redirect http://www and naked http/https to https://www or https://serverfault.com/questions/579916/nginx-redirect-https-www-to-https-non-www-without-untrusted-connection-warn/579917#579917 for details.
This is a more graceful solution that I use. Requires one server block for the actual website, and one server block for the redirect from non-www/non-https to https://www.*.
server {
listen IP_ADDRESS:443 ssl;
server_name www.domain.com;
}
server {
listen IP_ADDRESS:80 ssl default_server;
listen IP_ADDRESS:443 ssl default_server;
return 301 https://www.domain.com$request_uri;
}
The default_server option is important, otherwise the first definition becomes the default which can work against your intentions of redirecting all requests other than www.domain.com. By using default_server, your redirect server block acts as a catch-all.
In my opinion though, you should NOT be using "www". You should be redirecting from www to non-www. www is a legacy thing that isn't relevant these days. You're perpetuating this irrelevant legacy by redirecting from non-www to www.
I have used rewrite on both server directive and it worked for me:
General Rewrite Directive non www to https wwww
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.$server_name$request_uri;}
SSL Rule directive for non www to https wwww
server {
listen 443 ssl;
server_name example.com;
return 301 https://www.$server_name$request_uri;}

Resources