Foreword
Based on Alpine Linux's Docker image, create an SSL certificate configuration test environment to familiarize yourself with Nginx's SSL configuration.
Ready to work
Dockerfile GitHub
FROM alpine:3.6
RUN apk add --no-cache python3 nginx curl openssl socat bash openrc &&\
mkdir /run/nginx &&\
touch /root/.bashrc &&\
echo "export PS1='\h:\w\\\$ '" >> /root/.bashrc &&\
echo "alias r='fc -e -'" >> /root/.bashrc &&\
echo "set -o vi" >> /root/.bashrc &&\
echo 'rc_provide="loopback net"' >> /etc/rc.conf &&\
rc-update add nginx default
VOLUME ["/tmp/sys/fs/cgroup","/sys/fs/cgroup"]
WORKDIR /root
CMD ["/sbin/init"]
Create Docker image alssltest
# 获取Dockerfile 并创建镜像
git clone [email protected]:suzhi82/Alpine-SSLTEST.git &&\
cd Alpine-SSLTEST &&\
docker build -t alssltest .
# 查看Docker 镜像列表
docker image ls
# 或者
docker images
Run Docker image alssltest
# 宿主机的8888 就当成80 来用,8001、8002 及8443 测试不同应用时用
docker run --name alssltest -itd \
-p 8888:80 -p 8443:8443 -p 8001:8001 -p 8002:8002 \
alssltest
parameter | Explanation |
---|---|
–name | Name the container for later use, otherwise you can only use the container ID |
-i | Get standard input STDIN, the container will always wait for user input without exiting |
-t | Prepare for docker attach, the table user is connected to a tty, otherwise the password will be displayed in plain text |
-d | detach, detach, that is, let the container run in the background |
-p | Port mapping, host port: container port, this parameter can be used multiple times to map multiple ports |
Connect Docker container alssltest
docker exec -it alssltest /bin/bash
Container alssltest internal adjustment
cat /etc/nginx/nginx.conf
You can finally see include /etc/nginx/conf.d/*.conf inside http ;
so, we can write the test .conf configuration files /etc/nginx/conf.d/
below, and then
# 将默认的配置备份起来不启用
mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
OpenSSL self-signed SSL certificate
SSL self-signed certificate generation
# 创建保存SSL 文件的目录
mkdir -p /etc/nginx/ssl_keys/openssl
cd /etc/nginx/ssl_keys/openssl
# 生成服务器端的私钥 (key 文件)
openssl genrsa -out server.key 1024
# 生成服务器端证书签名请求文件 (csr 文件),certificate signing request,自定义区域详见下表
openssl req -new -key server.key -out server.csr
# 生成证书文件 (crt 文件),csr 文件至此就没有用了
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
csr file attributes
自定义区域
Country Name (2 letter code) [XX]:CN--------------------------------- 证书持有者所在国家
State or Province Name (full name) []:BJ----------------------------- 证书持有者所在州或省份(可省略不填)
Locality Name (eg, city) []:BJ--------------------------------------- 证书持有者所在城市(可省略不填)
Organization Name (eg, company) []:NH-------------------------------- 证书持有者所属组织或公司
Organizational Unit Name (eg, section) []:.-------------------------- 证书持有者所属部门(可省略不填)
Common Name (eg, your name or your server's hostname) []:ceshi.com--- 域名
Email Address []:---------------------------------------------------- 邮箱(可省略不填)
challenge password:-------------------------------------------------- 自定义密码
An optional company name:-------------------------------------------- 可选公司名称
Nginx SSL configuration
# Nginx 配置文件
cat > /etc/nginx/conf.d/openssl.conf << EOF
server {
listen 8443 ssl;
server_name ceshi.com;
ssl on;
ssl_certificate /etc/nginx/ssl_keys/openssl/server.crt;
ssl_certificate_key /etc/nginx/ssl_keys/openssl/server.key;
index index.html index.htm;
location / {
root /home/app/code;
}
}
EOF
Access test files
mkdir -p /home/app/code/
cat > /home/app/code/index.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>Index</title>
</head>
<body>
<h1>What a good day!</h1>
</body>
</html>
EOF
# 测试Nginx 配置
nginx -t
# 重启Nginx 服务
rc-service nginx restart
# 或者
nginx -s reload
After restarting, you can access https: // server IP: 8443 on the browser, a Your connection is not private
dot appears Help me understand
, and then click below Proceed to 服务器IP (unsafe)
, appears to What a good day!
indicate successful access, but not trusted by the browser.
OpenSSL use supplement
# 去除key 文件中的密钥
openssl rsa -in jesonc.key -out jesonc_nopwd.key
# 符合苹果标准的签名文件,直接生成私钥key 和公钥crt,由于是自签所以省略了请求文件csr 的生成
openssl req -days 3650 -x509 -sha256 -nodes -newkey rsa:2048 -keyout new_server.key -out new_server.crt
# rsa:2048 是服务器私钥的算法,-sha256 是发给浏览器证书即公钥的算法,可用以下命令查看
openssl x509 -noout -text -in new_server.crt
Nginx troubleshooting supplement
The user started by Nginx must have read permission to the folder where the page file is located, otherwise a 403 error will be reported
cat /etc/nginx/nginx.conf
# 启动nginx 所用的用户
user nginx;
# 错误日志的存放路径
error_log /var/log/nginx/error.log warn;
OpenSSL use conclusion
Because it is self-signed, the certificate needs to be manually imported into the browser to be trusted. When generating the certificate application, all custom information can be directly returned by skipping, as long as the browser inputs the server's IP or the domain name and the domain name pointing to the IP The content of the website can be accessed through the corresponding port, and the user's security can be imagined. ?
acme.sh Get SSL Certificate
Obtain SSL certificate issued by regular channel CA
Freenom domain name transfer to Cloudflare management
Although you can apply for a certificate by adding a txt-type DNS record to freenom according to the cme.sh prompt, you have to operate it once for each renewal, which is more convenient than not using DNS API automation.
Get the free domain name from https://www.freenom.com first, and pay attention to the VPN of US IP.
It is nothing more than to register and enter the desired domain name-> Check Availability, generally the end of tk / ml / gq and so on are free.
Register and log in https://www.cloudflare.com, click on Home Add a Site
, enter the domain name obtained by signature, for example maybook.tk
, then press Add site, Select a plan, select Free $ 0 / month, continue all the way to the Change your nameservers
interface.
Log in to https://www.freenom.com, Services-> My Domains, select maybook.tk
Manage Domain,-> Management Tools- > Nameservers, select Use custom nameservers
and write to the following two servers.
amit.ns.cloudflare.com
amy.ns.cloudflare.com
Finally click Change Nameservers
.
Return to the Cloudflare Change your nameservers
page, click Done, check nameservers, if the page jumps, click the Re-check now button. It may take several hours for Freenom's domain name to be handed over to Cloudflare.
After Cloudflare takes over, there will be Email notification. After logging in to Cloudflare, the status will be Active maybook.tk
. Click on it.
The API Tokens of Get your API key in Overview Global API Key
can authorize third-party programs to manage dns settings, such as acme.sh
automatic application and renewal of SSL certificates.
Set domain name record
Cloudflare-> Home select maybook.tk-> DNS and add the following Records in order for later experimentation?
Type | Name | Content | TTL | Proxy status |
---|---|---|---|---|
A | maybook.tk | 139.180.167.52 | Auto | DNS only |
A | app1.maybook.tk | 139.180.167.52 | Auto | DNS only |
A | app2.maybook.tk | 139.180.167.52 | Auto | DNS only |
acme.sh installation and use
# 安装acme.sh
curl https://get.acme.sh | sh
# 使acme.sh 生效,重新进入容器也行
source ~/.bashrc
# 导入Cloudflare Token,即Global API Key,让acme.sh 控制DNS 记录以自动申请证书
export CF_Key="ba1a821xxxxxx42b603064xxxxxxx3443"
export CF_Email="[email protected]"
# 将非泛型域名放在第一位方便以后部署,因为* 是通配符。
# 用以下命令申请的SSL 证书会包含maybook.tk 及泛型*.maybook.tk 域名
acme.sh --issue --dns dns_cf -d maybook.tk -d *.maybook.tk
After the execution of acme.sh, the DNS API information will be saved to ~/.acme.sh/account.conf
, if it is wrong, delete the relevant content in the file, then unset the environment variables and then export the environment variables.
# 安装部署SSL 证书
acme.sh --installcert -d maybook.tk \
--key-file /etc/nginx/ssl_keys/maybook.tk.key.pem \
--fullchain-file /etc/nginx/ssl_keys/maybook.tk.cert.pem \
--reloadcmd "service nginx restart"
acme.sh --installcert
The path and other configuration of each installation will be saved in ~/.acme.sh/<domain>/<domain>.conf
it.
It may be --reloadcmd "service nginx force-reload"
necessary for other distributions to allow Nginx to re-read the configuration file.
Nginx SSL configuration
# 新建一个Nginx 配置acme.sh.conf
cat > /etc/nginx/conf.d/acme.sh.conf << EOF
server {
listen 8001 ssl;
server_name maybook.tk;
ssl on;
ssl_certificate /etc/nginx/ssl_keys/maybook.tk.cert.pem;
ssl_certificate_key /etc/nginx/ssl_keys/maybook.tk.key.pem;
index index.html index.htm;
location / {
root /home/app/code;
}
}
EOF
# 让Nginx 重新读取配置
nginx -s reload
New certificate access verification
Still use the previously created page to configure the new SSL certificate issued by the CA.
Type https://maybook.tk:8001
in the What a good day!
browser , and the browser displays a green lock to indicate that the SSL certificate is trusted.
Verify generic domain name
Nginx configuration file
# 创建两个server 都监听80 端口,根据不同的请求host 临时重定向302 到对应的https 链接
cat > /etc/nginx/conf.d/acme.sh.x.conf << EOF
server {
listen 80;
server_name app1.maybook.tk;
# 不使用301 永久重定向,因为如果后期地址改变需要清理浏览器端的Cookie 才能生效
return 302 https://$host:8001$request_uri;
}
server {
listen 80;
server_name app2.maybook.tk;
return 302 https://$host:8002$request_uri;
}
# 创建两个开启了SSL 的server,并将请求代理转发到对应的后台应用
server {
listen 8001 ssl;
server_name app1.maybook.tk;
ssl_certificate /etc/nginx/ssl_keys/maybook.tk.cert.pem;
ssl_certificate_key /etc/nginx/ssl_keys/maybook.tk.key.pem;
location / {
proxy_pass http://127.0.0.1:8801;
}
}
server {
listen 8002 ssl;
server_name app1.maybook.tk;
ssl_certificate /etc/nginx/ssl_keys/maybook.tk.cert.pem;
ssl_certificate_key /etc/nginx/ssl_keys/maybook.tk.key.pem;
location / {
proxy_pass http://127.0.0.1:8802;
}
}
EOF
Access test files
# 模拟应用1
mkdir /home/web1/
cd /home/web1/
cat > index.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>Index</title>
</head>
<body>
<h1>
<a href="/a1.html">a1.html</a><br/>
<a href="/a2.html">a2.html</a>
</h1>
</body>
</html>
EOF
cat > a1.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>A1</title>
</head>
<body>
<a href="/index.html">index.html</a>
<h1>A1A1A1</h1>
</body>
</html>
EOF
cat > a2.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>A2</title>
</head>
<body>
<a href="/index.html">index.html</a>
<h1>A2A2A2</h1>
</body>
</html>
EOF
# 模拟应用2
mkdir /home/web2/
cd /home/web2/
cat > index.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>Index</title>
</head>
<body>
<h1>
<a href="/b1.html">b1.html</a><br/>
<a href="/b2.html">b2.html</a>
</h1>
</body>
</html>
EOF
cat > b1.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>B1</title>
</head>
<body>
<a href="/index.html">index.html</a>
<h1>B1B1B1</h1>
</body>
</html>
EOF
cat > b2.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title>B2</title>
</head>
<body>
<a href="/index.html">index.html</a>
<h1>B2B2B2</h1>
</body>
</html>
EOF
Simulate background API
nohup python3 -m http.server 8801 > /dev/null 2>&1 &
nohup python3 -m http.server 8802 > /dev/null 2>&1 &
Test results and conclusion
URL | content |
---|---|
http://maybook.tk:8888 | "What a good day!" page in https format |
http://app1.maybook.tk:8888 | https form contains a1, a2 index page |
http://app2.maybook.tk:8888 | https form contains b1, b2 index pages |
In Nginx, multiple servers can monitor the same port at the same time, and then use server_name, which is a domain name or sub-domain name, to distinguish different services.
Listen to the container's port 80 (mapped to the host 8888), then transfer the http request to https (8001-8002), and then to the background application (8801-8802) according to the server_name.
The browser will compare whether the domain name entered in the address bar is the same as the domain name in the SSL certificate. If the domain name is the same and the certificate is trusted, access is allowed, otherwise a security prompt such as a self-signed certificate will appear.
A brief introduction to SSL mutual authentication
The difference between SSL two-way authentication and SSL one-way authentication
The two-way authentication SSL protocol requires that both the server and the user have certificates. The one-way authentication SSL protocol does not require the client to have a CA certificate. The specific process is the same as the above steps. It only needs to remove the server-side verification of the client certificate, and when negotiating a symmetric password scheme and a symmetric call key, the server sends it to the client. What is not encrypted (this does not affect the security of the SSL process) cipher scheme. In this way, the specific communication content of the two parties is encrypted data. If there is a third-party attack, only the encrypted data is obtained. To obtain useful information, the third party needs to decrypt the encrypted data. The security at this time is Rely on the security of the password scheme. Fortunately, the current cryptographic scheme is sufficiently secure as long as the communication key is long enough. This is why we emphasize the requirement to use 128-bit encrypted communication.
Generally Web applications use SSL one-way authentication, the reason is very simple, the number of users is extensive, and there is no need to verify the user's identity at the communication layer, generally at the application logic layer to ensure the user's legal login. But if it is an enterprise application docking, the situation is different, and the client (relatively speaking) may be required to be authenticated. At this time, SSL mutual authentication is required.
Cleanup
Stop and delete the Docker container
docker stop alssltest && docker rm alssltest
Delete Docker image alssltest
docker rmi alssltest:latest
Reference documents
Getting started
with Nginx using acme.sh to install the free SSL certificate online server deployment provided by Let's Encrypt
(front and back end)