【发布时间】:2018-04-08 22:47:36
【问题描述】:
作为前缀,我一直在使用以下堆栈并取得了巨大成功:
NGINX - 网络代理 SSL - 在 nginx 中配置 Pyramid Web 应用程序,由 gunicorn 提供服务
上面的组合效果很好,这是一个有效的配置。
server {
# listen on port 80
listen 80;
server_name portalapi.example.com;
# Forward all traffic to SSL
return 301 https://www.portalapi.example.com$request_uri;
}
server {
# listen on port 80
listen 80;
server_name www.portalapi.example.com;
# Forward all traffic to SSL
return 301 https://www.portalapi.example.com$request_uri;
}
#ssl server
server {
listen 443 ssl;
ssl on;
ssl_certificate /usr/local/etc/letsencrypt/live/portalapi.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/portalapi.example.com/privkey.pem;
server_name www.portalapi.example.com;
client_max_body_size 10M;
client_body_buffer_size 128k;
location ~ /.well-known/acme-challenge/ {
root /usr/local/www/nginx/portalapi;
allow all;
}
location / {
proxy_set_header Host $host;
proxy_pass http://10.1.1.16:8005;
#proxy_intercept_errors on;
allow all;
}
error_page 404 500 502 503 504 /index.html;
location = / {
root /home/luke/ecom2/dist;
}
}
现在,这就是我为面向公众的应用程序提供服务的方式,它运行良好。对于我所有的内部应用程序,我曾经简单地将用户引导到一个内部域示例:http://subdomain.company.domain,这在很长一段时间内都运行良好。
现在在 KRACK 攻击之后,虽然我们有一些非常彻底的防火墙规则来防止很多攻击,但我想强制所有内部流量通过 SSL,我不想使用自签名证书,我想要使用让我们加密,这样我就可以自动更新证书,这使得管理更容易(并且更便宜)。
为了使用 Let 加密,我需要有一个面向公众的 DNS 和服务器来执行 ACME 质询(用于自动更新)。现在再次在 nginx 中设置这是一件非常容易的事情,并且以下配置非常适合提供静态内容:
如果来自 Internet 的用户访问 intranet.example.com,它会显示一条禁止消息。但是,如果本地用户尝试,他们会被转发到 intranet.example.com:8002,并且端口 8002 仅在本地可用,因此外部用户无法访问此站点上的网页
geo $local_user {
192.168.155.0/24 0;
172.16.10.0/28 1;
172.16.155.0/24 1;
}
server {
listen 80;
server_name intranet.example.com;
client_max_body_size 4M;
client_body_buffer_size 128k;
# Space for lets encrypt to perform challenges
location ~ /\.well-known/ {
root /usr/local/www/nginx/intranet;
}
if ($local_user) {
# If user is local, redirect them to SSL proxy only available locally
return 301 https://intranet.example.com:8002$request_uri;
}
# Default block all non local users see
location / {
root /home/luke/forbidden_html;
index index.html;
}
# This server block is only available to local users inside geo $local_user
# this block listens on an internal port only, so it is never availble to
# external networks
server {
listen 8002 default ssl; # listen on a port only accessible locally
server_name intranet.example.com;
ssl_certificate /usr/local/etc/letsencrypt/live/intranet.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/intranet.example.com/privkey.pem;
client_max_body_size 4M;
client_body_buffer_size 128k;
location / {
allow 192.168.155.0/24;
allow 172.16.10.0/28; # also add in allow/deny rules in this block (extra security)
allow 172.16.155.0/24;
root /home/luke/ecom2/dist;
index index.html;
deny all;
}
}
现在,金字塔/nginx 的结合问题来了,如果我使用与上述相同的配置,但在 8002 上为我的服务器设置以下设置:
server {
listen 8002 default ssl; # listen on a port only accessible locally
server_name intranet.example.com;
ssl_certificate /usr/local/etc/letsencrypt/live/intranet.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/intranet.example.com/privkey.pem;
client_max_body_size 4M;
client_body_buffer_size 128k;
location / {
allow 192.168.155.0/24;
allow 172.16.10.0/28; # also add in allow/deny rules in this block (extra security)
allow 172.16.155.0/24;
# Forward all requests to python application server
proxy_set_header Host $host;
proxy_pass http://10.1.1.16:6543;
proxy_intercept_errors on;
deny all;
}
}
我遇到了各种各样的问题,首先在金字塔内部,我在视图/模板中使用了以下代码
request.route_url # get route url for desired function
现在使用带有上述设置的 request.route_url 应该会导致 https://intranet.example.com:8002/login 路由到 https://intranet.example.com:8002/welcome 但实际上,此设置会将用户转发到:http://intranet.example.com/welcome 同样这是不正确。
如果我将 route_url 与 NGINX 代理设置一起使用:
proxy_set_header Host $http_host;
我收到错误:NGINX 返回 400 错误:
400: The plain HTTP request was sent to HTTPS port
对:https://intranet.example.com:8002/ 的请求被还原为:http://intranet.example.com/login(省略端口和 https)
然后我使用了相同的 nginx 设置(标头 $htto),但我想我会改为使用:
request.route_path
我的理论是这应该强制所有内容保持在相同的 url 前缀上,并且只是将用户从 https://intranet.example.com:8002/login 转发到 https://intranet.example.com:8002/welcome,但实际上,此设置的执行方式与使用 route_url 的方式相同。
proxy_set_header Host $http_host;
然后在导航到 https://intranet.example.com:8002 时出现错误
400: The plain HTTP request was sent to HTTPS port
并且对:https://intranet.example.com:8002/ 的请求被还原为:http://intranet.example.com/login(省略端口和 https)
谁能协助正确设置,以便我在https://intranet.example.com:8002上提供我的申请
编辑:
也试过了:
location / {
allow 192.168.155.0/24;
allow 172.16.10.0/28; # also add in allow/deny rules in this block (extra security)
allow 172.16.155.0/24;
# Forward all requests to python application server
proxy_set_header Host $host:$server_port;
proxy_pass http://10.1.1.16:8002;
proxy_intercept_errors on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# root /home/luke/ecom2/dist;
# index index.html;
deny all;
}
结果相同。
【问题讨论】:
-
IRC 推荐的解决方案是使用
proxy_set_header Host $host:$server_port;。 -
是的,这也不起作用。删除 proxy_set_header 解决了这个问题。
标签: nginx pyramid gunicorn lets-encrypt