I have an nginx server running. I want it to redirect http://www.example.com to https://www.example.com, but not touch any other subdomains like http://foo.example.com.
For some reason, no matter what I add in the subdomain, it still gets rerouted. My webpage shows on www.example.com (as it should), but also on foo.example.com and example.com (as it shouldn't)
This is my example.com config file:
server {
listen 80;
server_name www.example.com;
# For debug
add_header X-debug-message "listen:80, server_name:www.example.com, redirect:https://$host$request_uri" always;
# Riderect
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name www.example.com;
# For debug
add_header X-debug-message "listen:443, server_name:www.example.com, redirected:https://$host$request_uri" always;
# SSL
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
# Redirect
location / {
proxy_pass http://192.168.1.224:80;
}
}
Going to www.example.com shows me my webpage as expected. But going to foo.example.com also gives me my webpage - which it shouldn't. example.com also gives me the webpage.
Opening www.example.com in my browser, I see the following http header (as expected):
X-debug-message: DEBUG: listen:443, server_name:www.example.com, redirected:https://www.example.com/
Opening foo.example.com in my browser, I see the following http header (not as expected):
X-debug-message: DEBUG: listen:443, server_name:www.example.com, redirected:https://foo.example.com/
How can I make my nginx only redirect www.example.com ?
Ensure that the dns record for foo.yourdomain.com is actually created with
dns provider
Create a second server block for the subdomain 'foo.example.com'
otherwise all request to port 80
will be redirected to available server block, which in your case
www.example.com - the server block should look like this:
server {
server_name foo.example.com;
location / {
root path/to/foo/index.html;
index index.html index.htm;
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;
try_files $uri $uri/ /index.html;
}
listen 443 ssl; # managed by Certbot
ssl_certificate
/etc/letsencrypt/live/example.com/fullchain.pem; # n
managed by Certbot
ssl_certificate_key
/etc/letsencrypt/live/nextoma.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
}
Add ssl certificate to the foo.example.com with the command:
certbot --nginx -d foo.example.com
Restart nginx and recheck foo.example.com again
You need to make the first entry listen on 443 for HTTPS and server name _ and return 404.
server {
listen 443 ssl;
server_name _;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_certificate /etc/nginx/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/nginx/certs/nginx-selfsigned.key;
location / {
return 404;
}
}
By having the typical HTTP to HTTPS redirect in the file (I have it as the last entry):
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
Then all HTTP requests get converted to the HTTPS counterparts. Then, if you request a subdomain that has not been configured in the NGINX configuration file, it will default to the first entry which returns a 404. All other configured subdomains, and the root domain, if you have that as an entry, will resolve correctly.
Also you can keep your wildcard DNS, which is more practical than having to add each subdomain as an entry, as you point out in your answer.
Thank you for all the comments!
For other readers, and future reference, this is now my enlightened understanding.
nginx treats the first entry in it's enabled-sites conf as a default route. Thus, the first entry
server {
listen 80;
server_name example.net www.example.net;
...
}
is in fact treated as
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
So, my mistake, was to add *.example.com -> MyIP to my DNS, and assuming nginx would just 404 all routes I didn't explicitly define. When in fact, it looks for a route that matches foo.example.com, and if it doesn't, routes it to the default route.
So, I now changed my DNS to explicitly handle all subdomains I want routed, and I list all of them explicitly in nginx.
Now - how I achieve my original plan - to just route *.example.com to my IP, and have nginx 404 all requests except the ones I excplicitly define - I still don't understand.
Explicitly routing all subdomains in the DNS is a bit less flexible, as I need to update the DNS and wait for the change to propagate if I want to test a new service internally. But, I guess that is fine for now.
I'm using the docker image from linuxserver called swag which contains an nginx reverse proxy and a Let's encrypt certbot. Quite some dockerized apps are not designed to be accessed via subdirectory proxying but instead need to be proxied to a subdomain (because otherwise js and css files are requested from the domain, not the subdirectory).
My goal is to make a service at 1.test.example.com available at example.com/1
The config for the subdomain looks like this and works fine:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /config/www;
index index.html index.htm index.php;
server_name 1.test.*;
include /config/nginx/ssl.conf;
client_max_body_size 0;
# some app
location / {
include /config/nginx/proxy.conf;
proxy_pass http://172.2.0.2:1234/;
}
}
My try for proxying to the subdomain looks like this but doesn't work as my browser returns "400 Bad request":
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /config/www;
index index.html index.htm index.php;
server_name _;
include /config/nginx/ssl.conf;
client_max_body_size 0;
# proxy to some app
location /1/ {
include /config/nginx/proxy.conf;
proxy_pass https://1.test.example.com;
proxy_set_header Host 1.test.example.com;
}
}
What is the correct way to do this using proxy_pass and without using rewrite?
I host a site in compute engine in google cloud with Nginx on Debian, I use a Bluehost domain and a Cloudflare SSL.
My site web sometimes works and sometimes not and show me this message: Your connection is not private.
what is the solution?
example.com file:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 302 https://$server_name$request_uri;
}
server {
# SSL configuration
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl on;
ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/private/key.pem;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm index.php;
ssl_client_certificate /etc/ssl/certs/cloudflare.crt;
ssl_verify_client on;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}
}
I think John H nailed it, seems you have a mixed content issue. You may end up having to edit as suggested, but I'd first recommend trying to enable "Automatic HTTPS Rewrites" on the Crypto tab. Other mixed content suggestions here, https://community.cloudflare.com/t/community-tip-fixing-mixed-content-errors/42476.
If you have more questions about Cloudflare, visit the Cloudflare Community, https://community.cloudflare.com/t/community-tip-welcome-stackoverflow-visitors/99529."
I'm new to ngnix, maybe my problem is trivial but I can't get any way to diagonize where is the issue :
We migrated our web app from version 0.6.4 to 0.6.5. To be sure, our users don't keep old files in their browser cache, we prefix our url with the version number to force refreshing : eg https://qa.share.place/v0.6.5/place/(:placeId)
So I need people who bookmarked a url with the old url format
https://qa.share.place/v0.6.4/place/(:placeId) to be redirected to the new url.
I attempted a url rewrite this way:
server {
server_name qa.share.place;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server ipv6only=on;
ssl_certificate /etc/letsencrypt/live/qa.share.place/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/qa.share.place/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/qa.share.place/fullchain.pem;
include /etc/nginx/snippets/ssl.conf;
#https://forum.nginx.org/read.php?2,267685,267686
#keepalive_timeout 70;
root /home/ubuntu/share_place/bin/static;
index index.html index.htm index.nginx-debian.html;
#return 302 https://www.share.place/upgrade;
gzip on;
gzip_min_length 1000;
gunzip on;
client_body_in_file_only clean;
client_body_buffer_size 32K;
sendfile off;
send_timeout 300s;
client_max_body_size 1000M;
#================ here is my issue
rewrite ^(\/v0\.6\.4\/)(.*) /v0.6.5/$2 last;
location /v0.6.5 {
proxy_pass http://localhost:3000/ ;
}
}
The issue, is that I have a 404, and I don't know how to log where the url was redirected (rewritten) to understand what's happening behind the wall.
Is the routing location /v0.6.5 {} still interpreted after the rewrite? or does the rewrite skip any treatments after it happens?
Any help please
Having a server block that should serve content both for http and https :
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
include snippets/certificate.conf;
include snippets/ssl-params.conf;
root ...
}
Is it possible configure the gzip compression off only for the https connection in the same server block, or do i have to slipt them ?
EDIT:
Actually could be done checking the request scheme inside the location block and set gzip to off if is equal to https:
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
include snippets/certificate.conf;
include snippets/ssl-params.conf;
location / {
if ($scheme = "https") {
gzip off;
}
try_files $uri $uri/ =404;
}
...
}
problem is it seem safe only use rewrite and return statement inside if block https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
Well it is not possible
Syntax: gzip on | off;
Default:
gzip off;
Context: http, server, location, if in location
As you can see it can be used only in these blocks http, server, location, if in location. And it doesn't allow any parameters for the value
nginx: [emerg] invalid value "$gzip_flag" in "gzip" directive, it must be "on" or "off" in /usr/local/openresty/nginx/conf/nginx.conf:15
So you have to split your servers into two. But since rest of your stuff will be common, you can put everything in a include file. Include that file in both server locations