Proxy HTTP requests to an HTTPS server in nginx - ssl

I would like to set up an nginx instance which would proxy HTTP requests starting in /api to an HTTPS server, but the /api URL segment should be omitted out.
For example, the instance should listen to localhost:9817. And if it receives a request to http://localhost:9817/api/auth, it should proxy it as https://api.com:8443/auth.
Here is my nginx config:
events {
worker_connections 1024;
}
http {
server {
listen 9817;
server_name localhost;
location /api {
rewrite ^/api(/.*) $1 break;
proxy_pass https://api.com:8443;
proxy_set_header Host $host;
proxy_http_version 1.1;
}
location / {
root "D:/Project/dist";
try_files $uri $uri/ /index.html;
}
}
}
However, I get the following error in error.log:
2020/01/16 17:54:22 [error] 420512#426216: *31 peer closed connection in SSL handshake (10054: An existing connection was forcibly closed by the remote host) while SSL handshaking to upstream, client: 127.0.0.1, server: localhost, request: "POST /api/auth HTTP/1.1", upstream: "https://16.53.35.38:8443/auth", host: "localhost:9817", referrer: "http://localhost:9817/"
What is the reason for this error? How can I fix it or set up proxying as I want to?

I got same problem.
I found magic action to fix it in this stackoverflow answer
"Try adding proxy_ssl_server_name on; to your proxy_pass block and see if it helps"
It was in my nginx.conf
location / {
proxy_pass https://$http_x_forwarded_to;
}
After editing it became
location / {
proxy_pass https://$http_x_forwarded_to;
proxy_ssl_server_name on;
}
I can enjoy life again

Related

How to serve devpi with https?

I have an out-of-the-box devpi-server running on http://
I need to get it to work on https:// instead.
I already have the certificates for the domain.
I followed the documentation for nginx-site-config, and created the /etc/nginx/conf.d/domain.conf file that has the server{} block that points to my certificates (excerpt below).
However, my devpi-server --start --init is totally ignoring any/all nginx configurations.
How do i point the devpi-server to use the nginx configurations? Is it even possible, or am I totally missing the point?
/etc/nginx/conf.d/domain.conf file contents:
server {
server_name localhost $hostname "";
listen 8081 ssl default_server;
listen [::]:8081 ssl default_server;
server_name domain;
ssl_certificate /root/certs/domain/domain.crt;
ssl_certificate_key /root/certs/domain/domain.key;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
gzip on;
gzip_min_length 2000;
gzip_proxied any;
gzip_types application/json;
proxy_read_timeout 60s;
client_max_body_size 64M;
# set to where your devpi-server state is on the filesystem
root /root/.devpi/server;
# try serving static files directly
location ~ /\+f/ {
# workaround to pass non-GET/HEAD requests through to the named location below
error_page 418 = #proxy_to_app;
if ($request_method !~ (GET)|(HEAD)) {
return 418;
}
expires max;
try_files /+files$uri #proxy_to_app;
}
# try serving docs directly
location ~ /\+doc/ {
try_files $uri #proxy_to_app;
}
location / {
# workaround to pass all requests to / through to the named location below
error_page 418 = #proxy_to_app;
return 418;
}
location #proxy_to_app {
proxy_pass https://localhost:8081;
proxy_set_header X-outside-url $scheme://$host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}
This is the answer I gave to the same question on superuser.
Devpi doesn't know anything about Nginx, it will just serve HTTP traffic. When we want to interact with a web-app via HTTPS instead, we as the client need to talk to a front-end which can handle it (Nginx) which will in turn communicate with our web-app. This application of Nginx is known as a reverse proxy. As a reverse proxy we can also benefit from Nginx's ability to serve static files more efficiently than getting our web-app to do it itself (hence the "try serving..." location blocks).
Here is a complete working Nginx config that I use for devpi. Note that this is /etc/nginx/nginx.conf file rather than a domain config like yours because I'm running Nginx and Devpi in docker with compose but you should be able to pull out what you need:
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Define the location for devpi
upstream pypi-backend {
server localhost:8080;
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.co.uk; # This is the accessing address eg. https://example.co.uk
root /devpi/server; # This is where your devpi server directory is
gzip on;
gzip_min_length 2000;
gzip_proxied any;
proxy_read_timeout 60s;
client_max_body_size 64M;
ssl_certificate /etc/nginx/certs/cert.crt; Path to certificate
ssl_certificate_key /etc/nginx/certs/cert.key; Path to certificate key
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/pypi.access.log;
# try serving static files directly
location ~ /\+f/ {
error_page 418 = #pypi_backend;
if ($request_method !~ (GET)|(HEAD)) {
return 418;
}
expires max;
try_files /+files$uri #pypi_backend;
}
# try serving docs directly
location ~ /\+doc/ {
try_files $uri #pypi_backend;
}
location / {
error_page 418 = #pypi_backend;
return 418;
}
location #pypi_backend {
proxy_pass http://pypi-backend; # Using the upstream definition
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-outside-url $scheme://$host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
With Nginx using this configuration and devpi running on http://localhost:8080, you should be able to access https://localhost or with your machine with appropriate DNS https://example.co.uk. A request will be:
client (HTTPS) > Nginx (HTTP) > devpi (HTTP) > Nginx (HTTPS) > client
This also means that you will need to make sure that Nginx is running yourself, as devpi start won't know any better. You should at the very least see an Nginx welcome page.

nginx auth_request to remote authentication script

I'm trying to setup a nginx reverse proxy in front of some internal servers with auth_request to protect them from unauthorized users. I have an authentication script running at 192.168.1.101/scripts/auth/user.php which is accessed inside of the /auth block. The problem is that I'd like to use a named location rather than matching URI so that there is no risk of URI collision with the internal service (which I don't control). The following works:
server {
listen 80;
server_name private.domain.com;
location /auth {
proxy_pass http://192.168.1.101/scripts/auth/user.php;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
location / {
auth_request /auth;
proxy_pass http://internal.domain.com;
}
}
I'd like to replace the /auth with #auth however when I do nginx throws an error during relad. I've read that the fix is the replace the proxy_pass inside of the auth location with just the IP address however when I do that the auth_request never makes it to the script. Any thoughts on the correct way to proceed with this configuration?
Due some nginx restrictions named locations can't be used for subrequest. You can prevent outside access of auth location with internal config option. Try this config:
location = /scripts/auth/user.php {
internal;
proxy_pass http://192.168.1.101;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
location / {
auth_request /scripts/auth/user.php;
proxy_pass http://internal.domain.com;
}

Assets Directory returning 404 via SSL on unicorn nginx Ubuntu 14

This is similar question to this one, but suggested answer does not work.
I have confirmed that the assets exist, and restart nginx as well as unicorn service.
$ service nginx restart
$ service unicorn_app_name restart
This is my /etc/nginx/sites-enabled/[app_name] config.
upstream unicorn {
server unix:/home/unicorn_user/apps/app_name/shared/sock/unicorn.unicorn_user.sock fail_timeout=0;
}
server {
listen 80;
server_name staging.mydomain.org mydomain.org;
# Do not use a /tmp folder or other users can obtain certificates.
location '/.well-known/acme-challenge' {
default_type "text/plain";
root /etc/letsencrypt/webrootauth;
}
location / {
rewrite ^/(.*) https://staging.mydomain.org/$1 permanent;
}
}
ssl_certificate /etc/letsencrypt/live/staging.mydomain.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/staging.mydomain.org/privkey.pem;
server {
listen 443 ssl;
server_name www.staging.mydomain.org;
rewrite ^(.*) https://staging.mydomain.org/$1 permanent;
}
server {
listen 443 ssl;
server_name staging.mydomain.org;
root /home/unicorn_user/apps/app_name/current/public;
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_pass http://unicorn;
}
location ~ ^/(assets)/ {
gzip_static on;
expires max;
add_header Cache-Control public;
#add_header Last-Modified "";
#add_header ETag "";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 60;
}
Seeing the 404's in the error and access logs. For example:
2016/05/18 07:46:01 [error] 2490#0: *4 open() "/home/unicorn_user/apps/app_name/current/public/assets/loading.gif" failed (2: No such file or directory), client: ip_address, server: staging.mydomain.org, request: "GET /assets/loading.gif HTTP/1.1", host: "staging.mydomain.org", referrer: "https://staging.mydomain.org/path/to/page"
Permissions on all the assets are 644 and 755, owned by unicorn_user and in same group name.
Can anyone make another suggestion for a log or configuration to check, a service to restart? Is there an nginx config misconfiguration?
the 404 i was getting was because one particular asset, loading.gif was generated in current/app/assets/ while the server is looking in current/public/assets/.
I had assumed that other javascript errors were being caused because of this setting, but it's simply because my Rails ignorance is so vast, I wasn't sure where to look for what.

Websockets behind Apache and Nginx proxy connection not upgraded

I have a problem. Apache listens on a white ip and proxies all requests /ssd on nginx that proxies requests /city-dashboard to another server with websockets. In apache config:
ProxyPass /ssd/ http://10.127.32.24
ProxyPassReverse /ssd/ http://10.127.32.24
nginx config:
on nginx.conf:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/nginx/conf.d/*.conf;
on default.conf
location /city-dashboard/stream {
proxy_pass http://10.127.32.24:5000/stream;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
Request headers:
Connection: Upgrade
Upgrade: Websocket
Response headers:
Connection: close
Status Code 400 Bad Request
what am I doing wrong?
What about authorization header in request ? it seems authorization problem.

Overwrite Cache-Control: Private in Nginx

Just wonder if there is any way to overwrite / drop the response back Cache-Control: private from a proxied remote server. The setup architecture looks like this (yes, it's a reverse-proxy set up):
[my server] --> [remote server]
The setting for my server site-available/default:
server {
listen 80; ## listen for ipv4
listen [::]:80 default ipv6only=on; ## listen for ipv6
server_name localhost;
location / {
if ($arg_AWSACCESSKEY) {
proxy_pass http://localhost:8088;
}
try_files $uri $uri/ /index.php /index.html /index.htm;
}
# other setting goes here
}
The setting for my server site-available/remote:
server {
listen 8088; ## listen for ipv4; this line is default and implied
# Make site accessible from http://localhost/
# server_name localhost;
location / {
proxy_pass http://remoteserver;
proxy_set_header Host remoteserverhostname.com;
proxy_ignore_headers Cache-Control Expires;
proxy_pass_header Set-Cookie;
}
}
But Firebug still report the header contains Cache-Control: private. Did I missed something?
Thanks.
You want proxy_hide_header instead of proxy_ignore_headers