使用Nginx在Ghost博客上进行SSL重定向和身份验证

时间:2017-02-26 23:55:06

标签: ssl redirect nginx digital-ocean ghost

我在DigitalOcean上有一个关于Ghost的博客。 Nginx也提供了相同的配置文件:

server {
    listen 443 ssl;
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;

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

    include snippets/ssl-params.conf;

    location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:2825;
    }
}

证书是使用Let's Encrypt生成的,无论是有无www的域。 在Ghost config.js文件中,URL使用规则编写以获取SSL:https://example.com/ 问题是,当我进入我的博客时,我的域名没有使用wwww,正确登录并使用SSL,但是当我尝试使用https://www.example.com登录时,我收到了SSL证书身份验证错误。 我真的不明白这里可能出现的问题。 我需要在使用www进入我的域时重定向到域名,但没有www。我以前用其他应用程序节点做的这个操作没有问题,上面的配置代码相同。

5 个答案:

答案 0 :(得分:1)

我正在周末的一个很好的部分研究这个不便的解决方案,并设法找到解决方案。 Let的加密和Nginx中都没有错误,所有这些错误都指的是我的错误配置;但是,我不能不再认为这是一件奇怪的事情,即使不多说,我的解决方案也可以改进,这是我的Nginx配置文件:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    include snippets/ssl-params.conf;

    if ($http_host = www.example.com) {
            return 301 https://example.com$request_uri;
    }

    location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-NginX-Proxy true;
            proxy_pass http://localhost:8080/;
            proxy_ssl_session_reuse off;
            proxy_set_header Host $http_host;
            proxy_cache_bypass $http_upgrade;
            proxy_redirect off;
    }
}

为了避免拖动错误,完全删除我的虚拟机并从头开始创建它,还安装最新版本的Nginx for Debian,即1.10.3,这使我能够使用http2,这也是一种改进。

答案 1 :(得分:1)

一种解决方案是为www子域请求并安装第二个SSL证书。

<强>步骤:

  1. 打开您的nginx HTTP配置文件:sudo nano /etc/nginx/sites-available/example.com.conf。复制现有服务器块。保持第一个块不变,以便它继续适用于example.com。在第二个块中,在server_name行中包含www:server_name www.example.com;。保存&amp;关闭文件。

  2. 打开您的nginx SSL配置文件:sudo nano /etc/nginx/sites-available/example.com-ssl.conf。保持第一个块不变,以便它继续适用于example.com。在第二个块中,在server_name行中包含www,它将为您提供server_name www.example.com;。然后删除以ssl_certificatessl_certificate_key开头的行,因为我们不需要这些行,因为我们将为www子域请求新的SSL证书。保存&amp;关闭文件。

  3. 请求让我们为www子域加密SSL证书: sudo /etc/letsencrypt/acme.sh --issue --home /etc/letsencrypt --domain www.example.com -- webroot /var/www/ghost/system/nginx-root --reloadcmd "nginx -s reload" --accountemail exampleEmailAddress@example.com

  4. 重新打开您的nginx SSL配置文件:sudo nano /etc/nginx/sites-available/example.com-ssl.conf。返回您在步骤2中设置的www.example.com服务器块,然后重新添加ssl_certificate行:ssl_certificate /etc/letsencrypt/www.example.com/fullchain.cer;ssl_certificate_key /etc/letsencrypt/www.example.com/www.example.com.key;。保存&amp;关闭文件。

  5. 使用sudo nginx -s reload重新加载nginx,错误应该消失。

答案 2 :(得分:0)

您的第一个服务器块没有证书定义。因此,您可能希望复制ssl_certificate块中的ssl_certificate_keyserver语句。

如果这些是唯一的SSL server块,并且因为您有两个域的公共证书文件,则可以将ssl_certificatessl_certificate_key语句移至{{1} } level并允许它们被http块继承。

server

有关详情,请参阅this document

答案 3 :(得分:0)

(OP确实要求在另一个答案的评论中查看我的nodejs代理代码。)

在我们进入nodejs代理之前,我们应该检查几件事:

证书

您的证书是否适用于包含和不包含www?

的证书

如果您的证书仅在没有www(或反过来)的情况下有效,那么没有代理(nginx或我的或任何其他)设置可以提供帮助。因为SSL / TLS握手发生在重定向之前。在任何重定向发生之前,浏览器会立即投诉。最终用户在浏览器中看到证书错误。

我的两者都有效,您可以查看我的博客https://johnsiu.comhttps://www.johnsiu.com。重定向发生时没有任何证书抱怨。

DNS

使用和不使用www时,您的DNS设置是否正确?它们应指向相同的IP地址。

我想知道这是否与ERR_SOCKET_NOT_CONNECTED错误有关。

Nodejs代理

它托管在ghithub:https://github.com/J-Siu/ghost-https-nodejs-proxy

我刚完成微调我的nodejs代理,以下是最新版本:

// HTTPS

const fs = require('fs');
const url = require('url');
const http = require('http');
const https = require('spdy'); // http2 support
const proxy = require('http-proxy').createProxyServer();
const compression = require('compression');
const ex = require('express')();
const fqdn = '<your domain name here>';

// Fill in your certificate files
const serverKey = '<KEY file>';
const serverCrt = '<CRT file>';
//const serverCa='<CA file>';

const httpsOptions = {
	key: fs.readFileSync(serverKey),
	cert: fs.readFileSync(serverCrt),
	//	ca: fs.readFileSync(serverCa),
	ciphers: [
		"ECDHE-RSA-AES256-SHA384",
		"DHE-RSA-AES256-SHA384",
		"ECDHE-RSA-AES256-SHA256",
		"DHE-RSA-AES256-SHA256",
		"ECDHE-RSA-AES128-SHA256",
		"DHE-RSA-AES128-SHA256",
		"HIGH",
		"!aNULL",
		"!eNULL",
		"!EXPORT",
		"!DES",
		"!RC4",
		"!MD5",
		"!PSK",
		"!SRP",
		"!CAMELLIA"
	].join(':'),
};

// Ghost Proxy configuration

proxy.on('proxyReq', function (proxyReq, req, res, options) {

	// Ngix: proxy_set_header Host $http_host;
	proxyReq.setHeader('Host', req.headers.host);

	// Ngix: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxyReq.setHeader('X-Forwarded-For', req.connection.remoteAddress);

	// Ngix: proxy_set_header X-Forwarded-Proto $scheme;
	proxyReq.setHeader('X-Forwarded-Proto', 'https');

});

ex
	.use(compression())
	.use((req, res) => {
		if (req.header.host == fqdn) {
			proxy.web(req, res, { target: 'http://localhost:2368' });
		} else {
			res.writeHead(301, { 'location': 'https://' + fqdn + req.url });
			res.end();
		}
	})

// HTTPS Server

https.createServer(httpsOptions, ex).listen(443, '0.0.0.0');

// HTTP Redirect to HTTPS

http.createServer(function (req, res) {
	res.writeHead(301, { 'location': 'https://' + fqdn + req.url });
	res.end();
}).listen(80, '0.0.0.0');

能够:

  1. 将任何http流量重定向到https(我这里没有检查网址)
  2. 将任何https流量重定向到正确的fqdn(任何与我的fqdn不匹配的请求都会被重定向)
  3. ab test show~16request / sec
  4. 我为单盒单站点设置创建了这个,特别是在支持HTTPS / HTTP2时避免使用任何apache / nginx包。这可能无法完全满足您的需求,因为您正在进行多个站点。

答案 4 :(得分:0)

这是我的Nginx配置文件,我在这里使用Ghost提供博客。证书是使用Let的加密生成的,并且对两个域都有效。 在执行301重定向时给出了缺点,因为它无法正常工作,因为带有www的域告诉我证书无效,但是如果我尝试重定向到反向,从非www到www,它显示我是相同的消息,但对于没有www的域:

server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 80;
    server_name example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443;
    server_name example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443;
    server_name www.example.com;

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

    include snippets/ssl-params.conf;

    location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-NginX-Proxy true;
            proxy_pass http://localhost:9002/;
            proxy_redirect off;
    }
}

目前,我正在使用数字海洋的小滴,我在其中配置了3个字段A,字段A的值*指向虚拟机的IP,字段@也指向了IP的IP服务器,最后是一个值为www的字段A,它转到我服务器的IP。