让我们使用Nginx反向代理进行加密


45

介绍

我有一台开发服务器(当前正在运行Ubuntu 14.04 LTS),该服务器已经使用了一段时间,用于在不同端口上托管各种开发工具。因为可能很难记住端口,所以我决定对所有服务使用端口80,并根据主机名在内部进行端口转发。

除了编写domain.com:5432,我还可以直接通过sub.domain.com访问它

例如,正在使用sub.domain.com运行的端口7547的应用程序X具有以下nginx配置:

upstream sub {
    server 127.0.0.1:7547;
}

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    access_log /var/log/nginx/sub.log combined;
    location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:7547;
            proxy_set_header Authorization "";
    }
}

问题

给定我选择的当前配置结构,是否可以使用letencrypt并在https下运行不同的服务?


3
我写了一篇有关该主题的博客文章:tom.busby.ninja/letsecnrypt-nginx-reverse-proxy-no-downtime
Tom Busby

Answers:


81

是的,您可以向HTTP服务器发送nginx代理请求,然后自身通过HTTPS响应客户端。执行此操作时,您将要确保,无论谁是预期的攻击者,nginx <-> proxy连接都不会被嗅探到。足够安全的方法可能包括:

  • 代理到同一主机(与您一样)
  • 代理防火墙后面的其他主机

代理到公共Internet上的另一台主机并不足够安全。

以下是有关使用与代理服务器相同的Web服务器获取Let's Encrypt证书的说明。

从Let's Encrypt请求初始证书

修改您的server子句以允许.well-known从本地目录提供子目录,例如:

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    […]
    location /.well-known {
            alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here
        […]
    }
}

http://sub.domain.com/.well-known 让我们加密服务器将在其中寻找它所遇到的挑战的答案。

然后,您可以使用certbot客户端使用webroot插件(以root用户身份)从Let's Encrypt请求证书:

certbot certonly --webroot -w /var/www/sub.domain.com/ -d sub.domain.com -d www.sub.domain.com

您的密钥,证书和证书链现在将安装在 /etc/letsencrypt/live/sub.domain.com/

配置Nginx以使用您的证书

首先创建一个新的服务器子句,如下所示:

server {
    listen 443 ssl;

    # if you wish, you can use the below line for listen instead
    # which enables HTTP/2
    # requires nginx version >= 1.9.5
    # listen 443 ssl http2;

    server_name sub.domain.com www.sub.domain.com;

    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;

    # Turn on OCSP stapling as recommended at 
    # https://community.letsencrypt.org/t/integration-guide/13123 
    # requires nginx version >= 1.3.7
    ssl_stapling on;
    ssl_stapling_verify on;

    # Uncomment this line only after testing in browsers,
    # as it commits you to continuing to serve your site over HTTPS
    # in future
    # add_header Strict-Transport-Security "max-age=31536000";

    access_log /var/log/nginx/sub.log combined;

    # maintain the .well-known directory alias for renewals
    location /.well-known {
        alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here as in your port 80 configuration
        […]
    }
}

重新加载nginx:

service nginx reload

验证HTTPS现在通过访问工作https://sub.domain.com,并https://www.sub.domain.com在您的浏览器(和你特别希望的任何其他浏览器的支持),并检查他们不报告证书错误。

推荐:还可以查看raymii.org:Nginx上的SSL增强安全性, 并在SSL Labs中测试您的配置。

(推荐)将HTTP请求重定向到HTTPS

一旦确认您的网站可以使用该https://URL 的版本,而不是让某些用户因为访问而不提供不安全的内容http://sub.domain.com,请将其重定向到该网站的HTTPS版本。

将整个端口80 server子句替换为:

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    rewrite     ^   https://$host$request_uri? permanent;
}

现在,您还应该在端口443配置中取消注释此行,以使浏览器记住甚至不要尝试该站点的HTTP版本:

add_header Strict-Transport-Security "max-age=31536000";

自动续订您的证书

您可以使用此命令(以root用户身份)来续订certbot已知的所有证书,并使用新证书(与现有证书具有相同的路径)重新加载nginx:

certbot renew --renew-hook "service nginx reload"

certbot仅会尝试更新已过期60天以上的证书,因此非常安全(建议使用!)定期运行此命令(如果可能)自动运行。例如,您可以将以下命令放入/etc/crontab

# at 4:47am/pm, renew all Let's Encrypt certificates over 60 days old
47 4,16   * * *   root   certbot renew --quiet --renew-hook "service nginx reload"

您可以通过试运行来测试续订,它将与Let's Encrypt登台服务器联系以对联系您的域进行真实测试,但不会存储生成的证书:

certbot --dry-run renew

或者,您可以通过以下方法强制进行早期续订:

certbot renew --force-renew --renew-hook "service nginx reload"

注意:您可以根据需要进行多次空运行,但是实际续订要受“ 让我们加密”速率的限制


您的解决方案似乎对我不起作用。我的配置基本相同。它适用于goopen.tk,但不适用于www.goopen.tk
Alko

3
@Alko,答案的指示正确无误,并涵盖了此问题。使用certbot或其他任何工具时,您都不能忘记以www和非www格式指定域才能正常工作。
Paulo Coghi,2016年

在下location /.well-known,您需要忽略.well-known路径。使用alias /var/www/sub.domain.com,不使用alias /var/www/sub.domain.com/.well-known
gldraphael

1
任何人都可以向我解释为什么您要使用“ rewrite ^ https:// $ host $ request_uri?永久;” 而不是“返回301 https:// $ server_name $ request_uri;”
ZaxLofful

我发现我需要在位置的路径周围加上引号。location '/.well-known' {。不知道这是版本还是我的设置,但以防其他人卡住。
Frank V

2

是的,您可以nginx用作https的端点,并通过http与后端配合。例如我的配置:

server {
        server_name host;
        listen 443 ssl;
...
 location /svn/ {
            auth_ldap off;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://localhost:1080/svn/;
            proxy_redirect http://localhost:1080/ https://host/;
        }
...
}

但据我所知,通过加密,您必须在获得证书时指向所有子域,如果出现问题,则选择url https://host/service而不是https://service.host

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.