NextJs: Nginx returning 404 on API routes - nginx

I'm having an issue here where my NextJs API is returning 404 not found when executed from getInitialProps during a page reload in production.
The error message from my PM2 logs were mentioning the 404 not found was returned by Nginx.
It seems like NGINX is not able to detect my routes in /api/*.
This issue doesn't happen on local and I'm suspecting it is an issue or configuration I have missed out in nginx.
Here are my current versions that I am using
NextJs: 9.4.0
nginx/1.18.0 (Ubuntu) - On AWS EC2
UPDATE
I was able to scope down the issue into a SSL problem where if i disable my SSL in my nginx.conf file. The APIs are working fine. However I am still not able to find a solution to this.
nginx config file
server {
# Your domain
server_name mydomain.com;
# Proxy to nuxt renderer.
location / {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
# Redirect from /path/ to /path
rewrite ^/(.*)/$ /$1 permanent;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name mydomain.com;
return 404; # managed by Certbot
}
NextJs getInitialProps code
static async getInitialProps(context) {
const isServer = !!context.req
const { employerAccessToken } = nextCookie(context)
api.setBaseURL('/')
api.setAuthToken(employerAccessToken)
if (isServer) {
api.setCookie(nextCookie(context))
}
let apiResponse = await api.get('/api/employer/profile')
if (!apiResponse.ok) {
console.log('not OK');
console.log(apiResponse);
redirectToEmployerLogin(context)
return {}
}
let wrappedProps = {}
if (WrappedComponent.getInitialProps) {
wrappedProps = await WrappedComponent.getInitialProps(context)
}
}
api/employer/profile
const handler = async (req, res) => {
if (req.method == 'GET') {
try {
const { employerAccessToken } = nextCookie({ req, res })
api.setBaseURL(process.env.NEXT_PUBLIC_API_URL)
api.setAuthToken(employerAccessToken)
const apiResponse = await api.get('/employers/me', req.query)
console.log('apiResponse in /api/employer/profile');
console.log(apiResponse);
res.status(apiResponse.status).json(apiResponse.data)
} catch (error) {
logger.error(`message - ${error.message}, stack trace - ${error.stack}`)
res.status(500).json({})
}
}
}
PM2 Log Error

SOLVED
Apparently the issue is caused by nginx redirecting a server request from http to https however NextJs is not able to identify the route when its in https hence Nginx returns a 404 not found.
The solution would be to allow a proxy pass for localhost to maintain request at port 80 instead of forwarding all port 80 request to 443.
server_block conf
# redirect http to https
server {
listen 80;
listen [::]:80;
server_name 127.0.0.1 localhost;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name yourserver.com www.yourserver.com;
return 301 https://$server_name$request_uri;
}
server {
# listen on *:443 -> ssl;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name yourserver.com;
ssl_certificate /etc/letsencrypt/live/yourserver.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/yourserver.com/privkey.pem; # managed by Certbot
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
location / {
# reverse proxy for next server
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
# we need to remove this 404 handling
# because next's _next folder and own handling
# try_files $uri $uri/ =404;
}
location ~ /.well-known {
allow all;
}
}

Related

Nginx: rename URL after a redirection

My new website's address is foo.pro, when I go my old website bar.pro, it shows the content of the new foo.pro as expected but the URL remains bar.pro.
How to replace bar.pro by foo.pro in my Nginx configuration below ?
upstream foo_upstream {
server 127.0.0.1:3003;
keepalive 64;
}
server {
server_name www.foo.pro;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://foo_upstream;
proxy_redirect off;
proxy_read_timeout 240s;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.foo.pro/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.foo.pro/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.foo.pro) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name www.foo.pro;
return 404; # managed by Certbot
}
server {
listen 80;
server_name foo.pro;
return 301 https://www.foo.pro;
}
=== EDIT ===
I tried to add this directive in my conf:
server {
listen 80;
server_name bar.pro;
return 301 https://foo.pro;
}
But it's still not renaming the URL to foo.pro.

nginx with reverse-proxy and wildcard-subdomains

I become desparate... I want to write a configuration for nginx where shell.foo.org use a reverse proxy and *.shell.foo.org use a wildcard subdomain, so e.g. name1.shell.foo.org read /var/www/name1.shell.foo.org and name2.shell.foo.org read /var/www/name2.shell.foo.org. I tried a lot of versions but either the reverse proxy work or the wildcard subdomains.
My nginx-configuration is:
server {
listen 80;
listen [::]:80;
server_name ~^(www\.)(?<subdomain>.+).shell.foo.org$
~^(?<subdomain>.+).shell.foo.org$ ;
return 301 https://$host$request_uri;
}
server {
# SSL configuration
#
listen [::]:443 ssl ipv6only=on;
listen 443 ssl;
server_name ~^(www\.)(?<subdomain>.+).shell.foo.org$
~^(?<subdomain>.+).shell.foo.org$ ;
ssl_certificate /etc/letsencrypt/live/shell.foo.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shell.foo.org/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
root /var/www/$subdomain;
index index.html index.htm;
location / {
# if I comment this out the wildcard subdomains work;
# in this version, the reverse proxy work
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_read_timeout 300;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
}
root /var/www/$subdomain;
index index.html index.htm;
}
Anyone an idea where my mistake is?
Thanks,
bengoshi

How to SSL multiple ports on same server for single domain name using nginx

I am using let's encrypt to get SSL certificates and nginx as reverse proxy. Below is my nginx conf file that I am using :
server {
listen 443 http2 ssl;
server_name example.com;
access_log /var/log/nginx/example.com.log;
error_log /var/log/nginx/example.com.log;
location /.well-known/acme-challenge/ {
root /var/www/html/grafana; # Temp for generating letsencrypt
default_type text/plain;
}
location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
#Fix the “It appears that your reverse proxy set up is broken” error.
proxy_pass http://127.0.0.1:3000;
proxy_read_timeout 90;
proxy_redirect http://127.0.0.1:3000 http://example.com/;
#Required for new HTTP-based CLI
proxy_http_version 1.1;
proxy_request_buffering off;
}
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name example.com;
return 404; # managed by Certbot
}
============
My requirement here is :
I am running multiple applications on this server such as Jenkins, Gitlab, Grafana. And these applications are listening on different ports. The above file lets me redirect https://example.com to http://example.com:3000. But I would like to redirect my connections like this :
https://example.com:3000 -> http://example.com:3000
https://example.com:8080 -> http://example.com:8080
https://example.com:81 -> http://example.com:81
I have seen an environment doing it. But can't figure out how this was done.

Nginx: 404 Not Found error as reverse proxy

I am trying to configure Nginx as reverse proxy keeping Uvicorn behind it.
When I try to access "example.com", it returns the home page but gives 404 for all static files.
When I try to access any other endpoint like "example.com/blog", it returns "404 not found" page.
Here is the Nginx config:
server {
root /var/www/example.com/html;
index index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ =404;
#custom config
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://uvicorn;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 404; # managed by Certbot
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream uvicorn {
server unix:/tmp/uvicorn.sock;
}
What changes should I do to make it work?
As per the suggestion given by #richard-smith in the comment, I tried commenting out this line
location / {
#try_files $uri $uri/ =404; <-- here
#custom config
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://uvicorn;
}
and it worked fine. It is now able to serve all the endpoints.

Can I use WordPress blog as a subfolder of my main domain with a https NGINX?

I am developing a plateform on node/meteorjs stack and I want to add a WordPress blog for our website as well.
https//www.XXXXXX.com --> go to meteor app
https//www.XXXXXX.com/blog --> go to blog
I've got a NGINX front with https certificate
My NGINX config is :
`
server {
listen 80;
server_name XXXX.ovh;
return 301 https://XXXX.ovh$request_uri;
}
upstream meteorapp {
server 127.0.0.1:3000;
}
upstream blog {
server 52.16.157.100;
}
server {
listen 80;
server_name www.XXXX.ovh;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name XXXX.ovh;
return 301 https://www.XXXX.ovh$request_uri;
}
server {
listen 443 ssl default_server;
root /var/www/html;
server_name www.XXXX.ovh;
ssl_certificate /etc/letsencrypt/live/XXXX.ovh/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/XXXX.ovh/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
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_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
location /blog {
proxy_pass http://blog;
proxy_set_header Host $host;
}
location /wp-content {
proxy_pass http://blog;
proxy_set_header Host $host;
}
location /wp-admin {
proxy_pass http://blog;
proxy_set_header Host $host;
}
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
# try_files $uri $uri/ =404;
proxy_pass http://meteorapp;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-Proto http;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
}
location ~ /.well-known {
allow all;
}
}
My blog is hosted on other server and my meteor is in a docker container.
With this configuration, css and image of my blog doesn't work (i try to access the http ressources...
so I got some errors as :
Mixed Content: The page at 'https://www.cdispo.ovh/blog' was loaded over
HTTPS, but requested an insecure image 'http://www.XXXX.ovh/wp-content/themes/twentyseventeen/assets/images/header.jpg'. This content should also be served over HTTPS.
how can I do ?
You should instead use a subdomain in this manner "blog.myapp.com". Otherwise if the Meteor app controls the root ie "myapp.com" you will need to redirect all requests coming in to "myapp.com/blog" in your router.

Resources