Serve both static website & SPA (node.js) with NGINX - nginx

I need a way to serve both static html website and SPA using NGINX.
https://website.com -> should be the static index.html page.
https://website.com/register -> should point to SPA powered by node.js webserver.
So, if there's an appropriate static html route it should be served with NGINX, any other route should be served by node.js webserver.
e.g.
https://website.com/about -> served by NGINX because there's about.html
https://website.com/register -> served by node.js because there's no appropriate static page for this route (there's no register.html).
I've created the following configuration, but it doesn't seems to work properly.
upstream backend {
server localhost:8080;
}
server {
listen 80;
server_name website.com www.website.com;
root /var/www/website.com;
location = / {
try_files /index.html =404;
}
location = /index {
return 404;
}
location / {
try_files $uri/index.html =404 #backend;
}
location #backend {
proxy_pass http://backend;
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_redirect off;
}
}

Your configuration could probably be simplified to this:
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ #backend;
}
location #backend {
...
}

You could try something like
location / {
try_files $uri $uri.html $uri/ #backend;
}
Breaking it down for you. The try_files directive
Checks the existence of files in the specified order and uses the first found file for request processing;
So
$uri - look for the exact file as defined in the path. Useful for static files like css, images, js, etc..
$uri.html look for the exact file with a .html extension. This would get your about.html
$uri/ - looks for it to be a directory then uses the index directive to look for index or index.html
#backend - send to the proxied application would be responsible for returning 404

Related

How I combine multiple react apps in one app

I have two apps build in react using vite and I want to combine those two apps in one on the same port:
For example in nginx I want something like this:
http://localhost -> redirect to http://localhost:3000;
http://localhost/path-to-app2 -> redirect to http://localhost:4000;
What I tried with the apps in development mode:
server {
listen 80;
location / {
proxy_pass http://localhost:3000;
}
location /path-to-app2 {
proxy_pass http://localhost:4000;
}
}
also I tried with builded apps:
server {
listen 80;
location / {
root /usr/share/nginx/html/app1;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
location /path-to-app2 {
root /usr/share/nginx/html/app2;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
}
The problem is that all routes are redirected to location /. I also tried to change location / to location = / but also didn't work...
I also tried to app2 who has the path /path-to-app2 to add in package.json: "homepage": "/path-to-app2" but also didn't work. I don't succed to make the path / exact
I someone here who faced the same issue like me?

problem using variable in nginx location directive

good evening. i have a question regarding nginx and it is related to the location directive. i currently have this configuration in nginx
server {
server_name ~^(?<account>.+)\.domain\.com$;
root /var/www/html/folder-frontend/;
index index.html;
error_log /var/log/nginx/$account-access.log;
access_log /var/log/nginx/$account-access.log;
location / {
try_files $uri /index.html;
}
location /$account-backend/ {
proxy_pass http://service-backend/;
proxy_set_header HOST $account-backend.domain.co;
proxy_http_version 1.1;
}
}
this means that I have several domains with the ending tenant.domain.com(app1.domain.com, app2.domain.com). with the expression (?.+) I am getting part of the string in the url that interests me and then in the location directive use it to make a proxypass and redirect the requests. but this is not working, I know because when I put in the location what interests me (in this case would be location /app1-backend/) if redirects to the backend service that I have listening in another nginx.
My doubt is, can I use a variable in the location directive of nginx? I tried it that way specified and it does not work.
No, you can't use a variable as location directive argument, even in a regex matching ones. You can try a workaround like
server {
server_name ~^(?<account>.+)\.domain\.com$;
root /var/www/html/folder-frontend/;
index index.html;
error_log /var/log/nginx/$account-access.log;
access_log /var/log/nginx/$account-access.log;
location / {
try_files $uri /index.html;
}
location ~ ^/(?<prefix>[^.]+)-backend(?<suffix>/.*) {
if ($prefix != $account) {
return 404;
}
proxy_pass http://service-backend$suffix$is_args$args;
proxy_set_header HOST $prefix-backend.domain.co;
proxy_http_version 1.1;
}
}

Nginx - How to serve a static file to a particular user agent?

I am trying to restrict access to a particular json file for a certain user-agent using the configuration files in Nginx.
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
try_files $uri$args $uri$args/ /index.html;
}
location /v1/ {
proxy_pass http://127.0.0.1:8118;
proxy_pass_header Server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location = /v1/apischema {
root /usr/share/nginx/json;
if ($http_user_agent ~ useragentname) {
try_files /openapi.json;
break;
}
}
}
The idea is to restrict access to openapi.json for an internal user.
Please let me know where I am going wrong.
try_files can be used in a server or location block. See Context: in this document.
There are a number of ways to achieve this.
Using if:
location = /v1/apischema {
if ($http_user_agent ~ useragentname) {
rewrite ^ /openapi.json last;
}
}
location = /openapi.json {
internal;
root /usr/share/nginx/json;
}
The internal directive prevents this URI being accessed directly. See this caution on the use of if.
Or using map with try_files:
map $http_user_agent $apischema {
~useragentname /openapi.json;
default /nonexistant;
}
server {
...
location = /v1/apischema {
root /usr/share/nginx/json;
try_files $apischema =404;
}
}
See this document for details.

nginx proxy_pass to all pages

So I am using nginx to reverse proxy to another server. This wasn't serving static files, until I linked them in the location. The location block is super long, but looks similar to the code below. I'm sure that I'm doing this the wrong way, but it works, it's just tedious to write all the paths. I'm wondering if there's a better way.
location / {
proxy_pass www.example.com;
}
location /sytlesheet.css {
proxy_pass www.example.com/stylesheet.css;
}
location /page1 {
proxy_pass www.example.com/page1;
}
#this goes on and on
Is there a way to get everything past the '/' for example 'page1', and pass that to the proxy without manually typing it?
I'm hoping there's something a way to use a variable or something to link all the pages and resources with a single location block:
location / {
proxy_pass www.example.com;
}
location /$variable {
proxy_pass www.example.com/$variable;
}
Thanks!
You should use following code
location / {
# First attempt to serve request as file, then
# as directory, then fall back to proxy
try_files $uri $uri/ #proxy;
}
location #proxy {
proxy_pass www.example.com;
}
Check this out.
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://www.example.com;
}

Serving a.html from apache while requesting b.html

I'm creating a nginx reverse proxy to apache. Apache runs on port 8080 and nginx on 80.
I hope to achieve the following;
When I request the page http://server/test.html it should be proxyed to http://server:8080/unknown.html
Later on I'll do some eval stuff on the pages and redirect the users to the right pages, but I can't even get this to work. I get the test.html back as response all the time.
My nginx config:
server {
listen 80;
root /var/www/;
index index.php index.html index.htm;
server_name example.com;
location / {
# try_files $uri $uri/ /index.php;
}
location ~ \.html$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
#rewrite ^/unknown.html;
proxy_pass http://127.0.0.1:8080;
proxy_redirect http://127.0.0.1/test.html http://127.0.0.1:8080/unknown.html;
}
location ~ /\.ht {
deny all;
}
}
I have zero experience yet, but I'm eager to learn how to get this working...
Firstly, the proxy_redirect directive is the opposite of what you need. It is only used to rewrite the Location response headers in 3xx responses from upstream. See this document for details.
You can use a rewrite ... break statement within the location block that performs the proxy_pass, for example:
location ... {
rewrite ^/test.html$ /unknown.html break;
proxy_pass ...;
}
See this document for details.

Resources