NGINX SSL HTTPS configuration

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 privatedot 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 nameserversinterface.

Log in to https://www.freenom.com, Services-> My Domains, select maybook.tkManage Domain,-> Management Tools- > Nameservers, select Use custom nameserversand write to the following two servers.

amit.ns.cloudflare.com
amy.ns.cloudflare.com

Finally click Change Nameservers.

Return to the Cloudflare Change your nameserverspage, 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 Keycan authorize third-party programs to manage dns settings, such as acme.shautomatic 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 Instructions

# 安装acme.sh
curl  https://get.acme.sh | sh

# 使acme.sh 生效,重新进入容器也行
source ~/.bashrc

DNS API

# 导入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 --installcertThe path and other configuration of each installation will be saved in ~/.acme.sh/<domain>/<domain>.confit.
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:8001in 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)

Published 27 original articles · praised 4 · visits 9695

Guess you like

Origin blog.csdn.net/yoshubom/article/details/99675743