In my Nginx configuration, I would like to keep one service to be accessible with http, while all the others should be accessed through https, and forced to ssl when trying to connect with http. This is my config:
server{
server_name localhost;
listen 80;
proxy_http_version 1.1;
location /services/ {
proxy_pass http://localhost:47440/;
}
listen / {
rewrite ^ https://$server_name$request_uri? permanent;
}
server{
server_name localhost_ssl;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/mycert.crt;
ssl_certificate_key /etc/nginx/ssl/mycert.key;
proxy_http_version 1.1;
location /db/ {
proxy_pass http://localhost_ssl:8084/;
}
}
My problem is that when trying to reload I get this error:
host not found in upstream "localhost_ssl" in /etc/nginx/nginx.conf:46
Any idea of why this happens?
It seems your DNS resolver is failing for some reason.
Try adding:
options single-request
to /etc/resolv.conf
This causes IPv6/v4 lookups to be done sequentially.
You got this error because nginx can't find the host "localhost_ssl". Indeed it doesn't exist unless you specify it with upstream directive (or in the hosts file I think).
You should set it to proxy_pass http://localhost:8084/; assuming your service is really listening on 127.0.0.1:8084.
Furthermore you may want to replace listen / { with location / {.
UPDATE : If you access your server with your IP (you don't have a domain name), then you can remove server_name directive :
server {
listen 80;
proxy_http_version 1.1;
location /services {
proxy_pass http://localhost:47440/;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri?; # Replace $server_name by $host
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/mycert.crt;
ssl_certificate_key /etc/nginx/ssl/mycert.key;
proxy_http_version 1.1;
location /db {
proxy_pass http://localhost:8084/;
proxy_set_header Host $host;
}
}
That config redirects requests received on port 80 to 443 if they don't match location /services. Requests received on port 443 are proxied if they match location /db.
But is this what you really want to achieve ? I mean a request on port 443 for /test would not match any location as there is only /db.
Related
I am trying configuring nginx (based on bitname/nginx:latest) as equivalent of Synology reverse proxy. This is due to missing wild-card redirect at Synology. While doing so, I face many issues; therfore I am requesting help for proper nginx configuration.
requirements
HTTPS upgrade
Redirect any wild-card subdomain (443) to a port 30'000
Hide the redirect port from user visibility
WebSockets must be supported (At Synology following header: Upgrade $http_upgrade AND Connection $connection_upgrade)
Example
Browser calls http://app1.my-example.com/
re-direct to https://app1.my-example.com:30000/
Browser displays: https://app1.my-example.com/, resolving via Port 30000
Current Code (not working so far)
# Test
server {
listen 8080;
server_name ~^(.*)\.my\-example.com$;
access_log /opt/bitnami/nginx/logs/yourapp_access.log;
error_log /opt/bitnami/nginx/logs/yourapp_error.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass https://$host:30000$request_uri/;
proxy_redirect off;
}
}
# Catch malicious requests
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
return 444;
}
I was able to solve my issue and would like to share the results. The only thing I do not get is, why redirect.my-example is OK as proxy_pass. It would hit the very same route (probably an endless-loop). Feedback/Improvement would be apreciated!
# custom code for hop by hop headers
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Upgrade connection
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
return 301 https://$host$request_uri;
}
# Redirect Subdomains (incl. Web-Socket)
server {
listen 8443 ssl;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
server_name my-example.de portal.my-example.de;
access_log /opt/bitnami/nginx/logs/yourapp_access.log;
error_log /opt/bitnami/nginx/logs/yourapp_error.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass https://redirect.my-example.de:30000;
proxy_redirect off;
}
}
# Catch malicious requests
server {
listen 8443 default_server;
listen [::]:8443 default_server;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
server_name _;
return 444;
}
I use a nginx instance in front of a Go service.
I want to redirect anything on port 80 to https. [done]
All (non-websocket) https requests at /* should go to https://localhost:8443/* [done]
All websocket https requests at /ws/* should go to https://localhost:8443/ws/* [missing]
My current config:
ssl_certificate ...
ssl_certificate_key ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.mydomain.com mydomain.com;
add_header Strict-Transport-Security "max-age=31536000";
location /ws { <--- This only works for /ws but not /ws/app1
proxy_pass http://localhost:8443/ws;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / { <--- Catches anything, even without wildcard ?!
proxy_pass http://localhost:8443;
}
}
server {
listen 443 ssl;
server_name *.mydomain.com;
return 444;
}
Why is this necessary ? Well, as I understand, you have to set the upgrade headers explicitly, so I guess you have to specify another location.
Ideally, I would just use one location, but then websockets are blocked (because upgrade headers never make it to the Go service...)
I'm not a nginx expert, so bear with me =).
[EDIT]
I got it working now. I'm not sure if its ok to always set_header Upgrade/Connection, even if it's not a websocket request, but my Go service doesn't give a ****, so it works for me =]
ssl_certificate ...
ssl_certificate_key ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.mydomain.com mydomain.com;
add_header Strict-Transport-Security "max-age=31536000";
location / { <--- Catches anything, even without wildcard ?!
proxy_pass http://localhost:8443;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
server {
listen 443 ssl;
server_name *.mydomain.com;
return 444;
}
Check out the article at https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
You are not using any location_match, so the match is a prefix match.
Use ~ as the location match modifier to have it interpreted as a regular expression.
The line location /ws should match every query starting with /ws.
I got Nginx server with HTTP (80 port) and HTTPS (443). But it is behind router and port forwarding is like 17014 for HTTP and 17004 for HTTPS. Redirection from HTTP to HTTPS works well but I have problems with request for HTTPS. For example I should see my application when I'm going to address "https://domain:17004" but I can see it only when I'm going to "https://domain:port/panel_admin/login". How to write correct rewrite rule or something? Here is my actually configuration:
server {
listen 80;
listen [::]:80;
rewrite ^ https://strona:port_1$request_uri? permanent;
}
server {
listen 443 ssl;
ssl_certificate /var/projekt/release_candidate/tags/0.4.1/trunk/zlight/webapp/cert/ssl.cert;
ssl_certificate_key /var/projekt/release_candidate/tags/0.4.1/trunk/zlight/webapp/cert/ssl.key;
location / {
proxy_pass http://localhost:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /static {
alias /var/projekt/release_candidate/tags/0.4.1/trunk/zlight/webapp/static/;
}
}
I solved the problem. Correct configuration looks like
server {
listen 80;
listen [::]:80;
rewrite ^ https://strona:port_https$request_uri? permanent;
}
server {
listen 443 ssl;
ssl_certificate /var/projekt/release_candidate/tags/0.4.1/trunk/zlight/webapp/cert/ssl.cert;
ssl_certificate_key /var/projekt/release_candidate/tags/0.4.1/trunk/zlight/webapp/cert/ssl.key;
location / {
proxy_pass http://localhost:4000;
proxy_set_header Host $host:port_http;
proxy_set_header X-Real-IP $remote_addr;
}
location /static {
alias /var/projekt/release_candidate/tags/0.4.1/trunk/zlight/webapp/static/;
}
}
So no rewrite. :)
I'm at my wit's end here. I've been fighting an nginx configuration for hours. Here are the two blocks I'm trying to use:
server {
listen 80 default_server;
location /health-check {
default_type 'text/plain';
access_log off;
return 200;
}
}
server {
listen 80;
location / {
return 301 https://$http_host$request_uri;
}
}
# other application servers/upstreams follow -- one is provided here for completeness,
# although the issue is almost certainly above
upstream quinoa-icehouse {
server 172.17.8.100:49153;
}
server {
server_name ~^quinoa-icehouse\.(?<domain>.+)$;
server_name_in_redirect off;
port_in_redirect off;
listen 443 ssl spdy;
listen 80;
ssl_certificate /etc/ssl/deis.cert;
ssl_certificate_key /etc/ssl/deis.key;
location / {
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_connect_timeout 30s;
proxy_send_timeout 1200s;
proxy_read_timeout 1200s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_next_upstream error timeout http_502 http_503 http_504;
add_header X-Deis-Upstream $upstream_addr;
proxy_pass http://quinoa-icehouse;
}
}
Note that I want the /health-check endpoint to work only when other server names aren't matched, but I want the 301 to occur whenever a server name is matched.
I seem to have tried every combination of these directives, only to get:
[INFO] - 2014/12/30 01:26:34 [warn] 39#0: conflicting server name "" on 0.0.0.0:80, ignored
Is there a way for me to accomplish what I seek? Thank you!!
Essentially, you are going outside the Nginx' defined parameters. You cannot have two default server blocks sitting on each other so to speak.
You can however achieve what you need by defining:
A catch all block listening on Port 80 to redirect all requests to Port 443
A catch all block listening on Port 443 for all unmatched domains
You then need to ensure the following:
Drop the "default_server" directive and rely on the position of the server blocks as in the example answer
Ensure other application servers/upstreams only listen on Port 443.
So your config should be something along these lines:
http {
[ ... ]
# Default to redirect from Port 80 to Port 443
server {
listen 80;
return 301 https://$host$request_uri;
}
# Default for unmatched domains on Port 443
server {
listen 443 ssl spdy;
ssl_certificate /etc/ssl/someCert.cert;
ssl_certificate_key /etc/ssl/someKey.key;
# Return 403, 404 or 444
return 403;
}
# Other servers.
# 1. These must be below this for this configuration to work.
# 2. None should listen on Port 80
server {
server_name ABC
listen 443 ssl spdy;
ssl_certificate /etc/ssl/someCert.cert;
ssl_certificate_key /etc/ssl/someKey.key;
[ ... ]
}
server {
server_name XYZ
listen 443 ssl spdy;
ssl_certificate /etc/ssl/someCert.cert;
ssl_certificate_key /etc/ssl/someKey.key;
[ ... ]
}
}
Refer to: Why is nginx responding to any domain name?
Note also that for simple server blocks that will just return simple responses, you don't need to have location blocks.
I'm trying to route traffic across multiple upstream servers on nginx like so:
upstream app_a {
server unix:/tmp/app_a.sock fail_timeout=10;
# For a TCP configuration:
# server localhost:8000 fail_timeout=0;
}
server {
#listen 80; ## listen for ipv4; this line is default and implied
#listen [::]:80 default ipv6only=on; ## listen for ipv6
index index.html index.htm;
server_name localhost;
root /home/ubuntu/app_a/www/staging/static;
location ~ ^/app_a/(.*)$ {
try_files $1 #proxy_to_app_a;
}
location #proxy_to_app_a {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_a;
}
Unfortunately the apps have no knowledge of full uris and expect to be sitting on root - which means i need to re-write the uri when passing to the app, which is why i thought this might work:
location ~ ^/app_a/(.*)$ {
try_files $1 #proxy_to_app_a;
}
the app works fine if location is just / (because of the aforementioned root issue), but this regex based solution doesnt seem to work. What do i need to do so the app gets / instead of app_a in the url?
Thanks
location /app_a/ {
rewrite /app_a/(.*) /$1 break;
proxy_set_header Host $http_host;
proxy_pass http://app_a;
}