Nginx Redirect hostname+location - redirect

my nginx config uses server_name _; to process all domains in a single server{} block and direct them all to the same codebase sitting in a single folder with a single index.php that sorts out the domain routing. (that's the way the web framework works with 100's of domains within a single cluster - cant change this).
One of the sites has 2 domains. One for each language, let's call them example.com and example.net. This site also has language-specific subfolders, let's call them: /com/ and /net/.
I need to create a redirect that ensures the language subfolder is only loaded on the matching domain.
eg, valid requests:
example.com/com/
example.net/net/
Any other request needs to be redirected based on the subfolder:
example.com/net/ -> example.net/net/
example.net/com/ -> example.com/com/
I cant do it with the framework because the folder contains all static files, so the router is never loaded. Can this be done in the nginx config?
Thank you
update, adding simplified version of my config:
server {
listen 80 default_server;
server_name _;
root /my/app/root;
index index.php index.html;
location / {
try_files $uri /index.php;
}
#PHP
location ~ \.php$ {
try_files $uri = 404;
[fastcgi stuff]
}
location = /favicon.ico {
access_log off;
log_not_found off;
}
location = /apple-touch-icon.png {
access_log off; log_not_found off;
}
location = /apple-touch-icon-precomposed.png {
access_log off;
log_not_found off;
}
}

I think that you will need 1 location block per subfolder (but have not tested it):
location /com {
proxy_pass http://upstream:8888/com;
proxy_set_header Host example.com;
proxy_pass_request_headers on;
}
location /net {
proxy_pass http://upstream:8888/net;
proxy_set_header Host example.net;
proxy_pass_request_headers on;
}

Solved it...
location /com/ {
if ($host = 'www.example.net') {
return 301 https://www.example.com$request_uri;
}
index index.html;
}
And the reverse for the other location/domain

Related

NGINX not respecting server_name regex

I have this nginx config.. i want it to accept all domains that have the word competitions in it and end with .com.au.. I have tested with a domain name that should NOT be accepted but it reaches the application.. is the server_name being ignore because I'm using a proxy?
server {
listen 80 default_server;
server_name ~^(.+)competitions?(.+)\.com\.au;
access_log /var/log/nginx/$host.access.log;
error_log /var/log/nginx/error.log;
if ($host !~* ^www){
rewrite ^/(.*)$ https://www.$host/$1 permanent;
}
location / {
proxy_no_cache 1;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8888;
try_files $uri $uri/ #proxy;
}
location #proxy {
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8888;
proxy_intercept_errors on;
recursive_error_pages on;
error_page 404 = #rewrite_proxy;
}
location #rewrite_proxy {
rewrite /(.*) /index.cfm?path=$1;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8888;
}
}
You'd have to remove the default_server from there, because this is a catch-all directive.And you still could setup another one server with the default_server directive, if required.
See How nginx processes a request for a more detailed explanation:
If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port.

nginx redirection depending on host

I have two domains website1.com and website2.com linked to my server.
I'm trying to do the following rewrite rules:
http://website1.com/ --> /website1/ (static)
http://website2.com/ --> /website2/ (static)
http://website1.com/app/ --> http://localhost:8080/web-app/web1/
http://website2.com/app/ --> http://localhost:8080/web-app/web2/
The user will be redirected to a static website served by nginx or an application server depending on the url.
Here's what I tried so far:
location / {
root html;
index index.html index.htm;
if ($http_host = website1.com) {
rewrite / /website1/index.html break;
rewrite (.*) /website1/$1;
}
if ($http_host = website2.com) {
#same logic
}
}
location /app/ {
proxy_pass http://localhost:8080/web-app/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($http_host = website1.com) {
rewrite /app/(.*) /$1 break;
rewrite /app /index.html;
}
if ($http_host = website2.com) {
#same logic
}
}
The static part seems to work fine, but the redirection web app part seems to serve index.html no matter what the requested file is.
This is not much of a definitive answer, but rather just my explanation of how I get nginx proxies to work.
root html;
index index.html index.htm;
server {
listen 80;
server_name website1.com;
location / {
alias html/website1;
}
location /app/ {
proxy_pass http://localhost:8080/web-app/web1/
}
}
server {
listen 80;
server_name website2.com;
location / {
alias html/website2;
}
location /app/ {
proxy_pass http://localhost:8080/web-app/web2/
}
}
The issue looks like it's being caused by these rewrites:
rewrite /app/(.*) /$1 break;
rewrite /app /index.html;
Using server blocks with server_names and the alias directive, we can do away with needing to use that much logic. Let me know if there's anything that is still not clear.
I think you're doing it wrong. If there is so much difference between the hosts, it would be cleaner and more efficient to have two distinct configurations, one for each host.
On the other hand, if your intention is to have multiple almost-identical configurations, then the correct way to go about it might be map, and not if.
Back to your configuration — I've tried running it just to see how it works, and one thing that you may notice is that the path you specify within the proxy_pass effectively becomes a noop once the $host-specific rewrite within the same context gets involved to change the $uri — this is by design, and is very clearly documented within http://nginx.org/r/proxy_pass ("When the URI is changed inside a proxied location using the rewrite directive").
So, in fact, using the following configuration does appear to adhere to your spec:
%curl -H "Host: host1.example.com" "localhost:4935/app/"
host1.example.com/web-app/web1/
%curl -H "Host: host2.example.com" "localhost:4935/app/"
host2.example.com/web-app/web2/
%curl -H "Host: example.com" "localhost:4935/app/"
example.com/web-app/
Here's the config I've used:
server {
listen [::]:4935;
default_type text/plain;
location / {
return 200 howdy;
}
location /app/ {
proxy_set_header Host $host;
proxy_pass http://localhost:4936/web-app/;#path is NOOP if $uri get changed
if ($host = host1.example.com) {
rewrite /app/(.*) /web-app/web1/$1 break;
rewrite /app /web-app/index.html;
}
if ($host = host2.example.com) {
rewrite /app/(.*) /web-app/web2/$1 break;
rewrite /app /web-app/index.html;
}
}
}
server {
listen [::]:4936;
return 200 $host$request_uri\n;
}

Nginx rewrite or internal redirection cycle while internally redirecting

I am having troubles with nginx.
Here is my config.
server {
listen 80;
listen [::]:80;
server_name www.test.local;
return 301 http://test.local$request_uri;
}
server {
server_name test.local;
root /usr/share/nginx/test/htdocs/web;
# error_log /var/log/nginx/test.error.log;
# access_log /var/log/nginx/test.access.log;
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri #rewriteapp;
}
location #rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
location ~ ^/app\.php(/|$) {
fastcgi_pass 172.17.0.1:48000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location /uploads/ {
root /usr/share/nginx/test/htdocs/web/uploads;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /images/ {
root /usr/share/nginx/test/htdocs/web/images;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /css/ {
root /usr/share/nginx/test/htdocs/web/css;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /js/ {
root /usr/share/nginx/test/htdocs/web/js;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /fonts/ {
root /usr/share/nginx/test/htdocs/web/fonts;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location = /favicon.ico {
return 204;
access_log off;
log_not_found off;
}
}
I want my locations as http://test.local/css/ link to /usr/share/nginx/test/htdocs/styles/ as i did it in my config.
But when im entering for example http://test.local/css/flow.css im getting next error:
2016/05/13 15:55:30 [error] 5#5: *64 rewrite or internal redirection cycle while internally redirecting to "/css/flow.css///////////", client: 192.168.99.1, server: test.local, request: "GET /css/flow.css HTTP/1.1", host: "test.local", referrer: "http://test.local/"
Whats the problem here?
You have two problems with your configuration.
The first problem is that your root directives are wrong, so the file is not found.
The second problem is that the default action is to add another / to the end of the URI.
You need to add a valid default action to your try_files directive, such as a 404 response:
try_files $uri $uri/ =404;
So, back to the first problem. Your configuration states that /css/example.css is located at /usr/share/nginx/test/htdocs/web/css/css/example.css. Notice that /css/ is replicated. Same goes for /images/, /js/ and /fonts/. See this document for details of the root directive.
In most configurations, it is sufficient to specify the root at the server block level and allow it to be inherited by almost all location blocks, rather than repeating it in each location.
Your question states that /css/ files should be found in /usr/share/nginx/test/htdocs/styles/. This requires an alias directive. See this document for details of the alias directive. For example:
location /css/ {
alias /usr/share/nginx/test/htdocs/styles/;
access_log off;
expires 30d;
}

Nginx: Redirect Conditional on Server Name and Sub Domain for Short URLs

I want to redirect conditionally based on the server name, but where I redirect to also depends on the subdomain. So for example, here is my basic config
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name company.com compa.ny;
ssl on;
ssl_client_certificate /etc/ssl/certs/godaddy_CA.crt;
ssl_certificate /etc/ssl/certs/wildcard.company.com.crt;
ssl_certificate_key /etc/ssl/private/wildcard.company.com.key;
ssl_prefer_server_ciphers on;
root /var/www/company;
access_log /var/log/nginx/nginx.access.log;
error_log /var/log/nginx/nginx.error.log;
client_max_body_size 8M;
location ^~ /application {
proxy_set_header HOST $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://127.0.0.1:8080;
}
}
I want to have something that looks for the short url host "compa.ny" and redirects to "company.com/shortUrldRedirector" and I also want to include the subdomain, so in dev or qa this will work correctly:
https://compa.ny/abc123 -> https://company.com/shortUrldRedirector/abc123
and
https://dev.compa.ny/abc123 -> https://dev.company.com/shortUrldRedirector/abc123
I see there is a $server_name config variable, but how do I accomplish the above redirects respecting the subdomain?
I would use map construction like this:
map $http_host $long_domain {
default company.com;
dev.compa.ny dev.company.com;
compa.ny company.com;
}
server {
...
return 301 https://$long_domain/shortUrldRedirector$request_uri;
}

How do I force redirect all 404's (or every page, whether invalid or not) to the homepage?

Currently every invalid page is 500 (Internal Server Error) because I probably messed up with my server block configuration.
I decided to shut down my website a while ago and created a simple one-page, thank-you homepage. However old links and external sites are still trying to access other parts of the site, which no longer exists.
How do I force redirect all non-homepage (any invalid URL) to the homepage?
I tried with the following block, but it didn't work:
location / {
try_files $uri $uri/ $document_uri/index.html;
}
My current configuration is (I don't even serve PHP files right now, ie homepage is simple html):
server {
server_name www.example.com example.com;
access_log /srv/www/example.com/logs/access.log;
error_log /srv/www/example.com/logs/error.log;
root /srv/www/example.com/public_html;
index index.php index.html;
location / {
try_files $uri $uri/ $document_uri/index.html;
}
# Disable favicon.ico logging
location = /favicon.ico {
log_not_found off;
access_log off;
}
# Allow robots and disable logging
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Enable permalink structures
if (!-e $request_filename) {
rewrite . /index.php last;
}
# Handle php requests
location ~ \.php$ {
try_files $uri = 404;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_send_timeout 900;
fastcgi_read_timeout 900;
fastcgi_connect_timeout 900;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Disable static content logging and set cache time to max
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
access_log off;
log_not_found off;
expires max;
}
# Deny access to htaccess and htpasswd files
location ~ /\.ht {
deny all;
}
# Deny access to hidden files (beginning with a period)
location ~ /\. {
access_log off; log_not_found off; deny all;
}
}
Setting the error page to the home page like this
error_page 404 /index.html;
has a small problem, the status code of the home page will be "404 not found", if you want to load the home page with a "200 ok" status code you should do it like this
error_page 404 =200 /index.html;
This will convert the "404 not found" error code to a "200 ok" code, and load the home page
The second method which #jvperrin mentioned is good too,
try_files $uri $uri/ /index.html;
but you need to keep 1 thing in mind, since it's the location / any asset that doesn't match another location and is not found will also load the index.html, for example missing images, css, js files, but in your case I can see you already have another location that's matching the assets' extensions, so you shouldn't face this problem.
To get a true redirect you could do this:
in server block define the error-page you want to redirect like this:
# define error page
error_page 404 = #myownredirect;
error_page 500 = #myownredirect;
Then you define that location:
# error page location redirect 302
location #myownredirect {
return 302 /;
}
In this case errors 404 and 500 generates HTTP 302 (temporary redirect) to / (could of course be any URL)
If you use fast-cgi for php or other these blocks must have the following added to send the errors "upstrem" to server-block:
fastcgi_intercept_errors on;
This solution for nginx hosted site:
Edit your virtual hosting file
sudo nano /etc/nginx/sites-available/vishnuku.com
Add this snippet in the server block
# define error page
error_page 404 = #notfound;
# error page location redirect 301
location #notfound {
return 301 /;
}
In your php block put the fastcgi_intercept_errors set to on
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
# intercept errors for 404 redirect
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Final code will look like this
server {
listen 80;
server_name vishnuku.com;
root /var/www/nginx/vishnuku.com;
index index.php index.html;
access_log /var/log/nginx/vishnuku.com.log;
error_log /var/log/nginx/vishnuku.com.error.log;
location / {
try_files $uri $uri/ /index.php?$args /;
}
# define error page
error_page 404 = #notfound;
# error page location redirect 301
location #notfound {
return 301 /;
}
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
location = /nginx.conf {
deny all;
}
}
Try adding the following line after your index definition:
error_page 404 /index.html;
If that doesn't work, try changing your try_files call to the following instead:
try_files $uri $uri/ /index.html;
Hopefully one of those works for you, I haven't tested either yet.
Must use
"fastcgi_intercept_errors on;"
along with the custom redirect location like
error_page 404 =200 /index.html or
as above
location #myownredirect {
return 302 /;
}
Try this:
error_page 404 $scheme://$host/index.html;
Hi first there are a lot of different ways to redirect all the 404 to the home page
this helps you in SEO
make such u use
fastcgi_intercept_errors on;
than add this following to your config
error_page 404 =301 http://yourdomain.com/;
error_page 403 /error403.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
Came here when I was looking to implement similar where I'm using Nginx as a reverse proxy to a self-hosted MinIO bucket, and none of the above answers have this. So, if you're using proxy_pass and are intercepting errors, you can also handle this logic to redirect to the index.html page.
Handling URLs such as:
http://localhost/ - 200 OK
http://localhost/index.html - 200 OK
http://localhost/non-existant/ - 404 Not Found
server {
listen 80;
server_name localhost;
location / {
rewrite ^/$ /static/index.html break;
proxy_intercept_errors on;
proxy_pass http://something-to-proxy/static/;
}
error_page 404 /index.html;
}
Another-correct way to redirect from error page to the home page. The setup example applies to the nginx server configuration file:
...
http {
...
server{
...
#Catch 40x errors:
error_page 400 401 402 403 404 = #RedirectToHome;
#Catch 50x errors:
error_page 500 501 502 503 504 = #RedirectToHome;
#We are now redirecting to the homepage of the site
location #RedirectToHome {
return 301 http://www.example.com;
#return 301 https://www.example.com;
#return 301 /;
}
...
}
}
You should avoid setting return 301 /; if port forwarding to the server was performed somewhere, because this nginx redirection will then be performed to the port on which the server is listening for incoming connections. Therefore, it is better to set the correct hostname(site name) in this configuration.