小白配置nginx的ssl证书,部署vue项目和springboot项目(docker)

813 阅读4分钟

ssl证书

申请免费的ssl证书

腾讯云免费的证书只能绑定域名。因为我之前已经购买了域名,又不想花钱,所以申请了腾讯云一年的免费证书。还有,购买的域名需要绑定到对应的云服务器上,并进行域名解析,这样nginx配置后,才能使用域名访问对应的网站。如下图: image.png

配置ssl证书

docker部署的nginx,需要先将nginx容器的目录映射到主机中,所以创建nginx容器需要将映射ssl目录的命令添加进去。虽然说ssl证书的默认存放路径是/etc/nginx,但直接将/etc/nginx映射到主机,会导致nginx无法运行,所以,这里是新建了/etc/nginx/ssl目录并映射到了主机中。完整命令如下:

docker run --name nginx -d \
-p 80:80 -p 443:443 \
-v /usr/local/docker/nginx/html:/usr/share/nginx/html:ro \
-v /usr/local/docker/nginx/logs:/var/log/nginx/:rw \
-v /usr/local/docker/nginx/config/conf.d:/etc/nginx/conf.d:rw \
-v /usr/local/docker/nginx/cert:/etc/nginx/ssl \
-d nginx

到自己的腾讯云服务器下载申请好的ssl证书,下载位置如下图: image.png image.png 切换到配置文件所在目录:

cd /usr/local/docker/nginx/config/conf.d

编辑default.conf,添加如下内容:

# 注意文件位置,是从/etc/nginx/下开始算起的
ssl_certificate /etc/nginx/ssl/bookswings.com_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/bookswings.com.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;

备注:这里标注的配置直接复制的腾讯云官方的,因为证书的原因,如果配错了,会导致无法访问

配置完成后,完整的配置文件如下:

server {
    listen       80;
    listen       443 ssl;
    server_name  域名; # _代表当前宿主机的地址

    # 注意文件位置,是从/etc/nginx/下开始算起的
    ssl_certificate /etc/nginx/ssl/ssl配置文件名称.crt;
    ssl_certificate_key /etc/nginx/ssl/ssl配置文件名称.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html; # nginx代理的根目录,被我映射到了/usr/local/docker/nginx/html,所以可以在此目录下新建index.html当作默认网页
        index  index.html index.htm;
    }

    location /user-management {
        alias /usr/share/nginx/html/user-management;
        index index.html index.htm;
        try_files $uri $uri/ /user-management/index.html;
    }

    location /user-management-service {
   #     proxy_pass http://ip:8088/user-management-service; #springboot项目未配置ssl时,这里的端口记得改成项目对应的哦
	proxy_pass https://域名:8443/user-management-service; # 8443端口是后端docker项目映射到主机的端口8443:443
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
    }
}

这里没有强制必须使用https才能访问网站,配置完成后,访问输入https://域名访问对应网站,配置成功的话,可以看到如下图的情况: image.png

但是访问后端接口,会无法访问,并提示如下错误:

# Mixed Content:'xxx' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'xxx'

是因为前端项目访问后端接口仍然使用的是http协议。需要将后端项目也改成https协议。

springboot项目配置ssl证书

springboot项目默认使用了tomcat服务器,所以需要前往腾讯云下载对应tomcat的ssl证书。如下图: image.png image.png

配置springboot项目

将下载好的ssl证书复制到/src/main/resources目录下,并在启动类中添加如下代码:

@Bean
public ServletWebServerFactory servletContainer() {

   TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {

      @Override
      protected void postProcessContext(Context context) {

         SecurityConstraint securityConstraint = new SecurityConstraint();
         securityConstraint.setUserConstraint("CONFIDENTIAL");
         SecurityCollection collection = new SecurityCollection();
         collection.addPattern("/*");
         securityConstraint.addCollection(collection);
         context.addConstraint(securityConstraint);
      }
   };
   tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
   return tomcat;
}
@Bean
public Connector initiateHttpConnector() {
   Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
   connector.setScheme("http");
   connector.setPort(80); // http端口
   connector.setSecure(false);
   connector.setRedirectPort(443); // application.properties中配置的https端口
   return connector;
}

在application.yml中添加如下配置:

server:
  port: 443 # 抛弃原有的自定义端口配置,ssl端口统一为443
  ssl:
    key-store: classpath:你的SSL证书文件名称
    key-store-password: keystorePass.txt中的密码
    key-store-type: PKCS12 # 固定的写法
  servlet:
    context-path: /user-management-service

启动项目,浏览器输入 https://localhost/user-management-service/对应的接口 访问成功

通过docker部署

编写Dockerfile:

# 基础镜像
FROM openjdk:8-jdk-alpine

# 往容器中添加jar包
COPY user-management-backend-1.1.jar user-management-backend.jar

RUN apk add --update font-adobe-100dpi ttf-dejavu fontconfig

# 启动镜像自动运行程序,这里的/user-management-backend.jar是上面拷贝到容器中的user-management-backend.jar
ENTRYPOINT ["java","-jar","/user-management-backend.jar"]

新建/usr/local/docker/docker-user-management-backend目录,将Dockerfile和jar包上传到该目录下,进行打包:

docker build -f Dockerfile -t user-management-backend:1.1 .

根据打包好的镜像创建容器,因为配置了ssl,所以需要同时暴露80端口和443端口:

docker run --name user-management-backend -d -p 8088:80 -p 8443:443 user-management-backend:1.1

创建好容器需要使用nginx进行反向代理,前端才能正常访问该项目,切换到nginx的配置文件目录下,编辑default.conf:

location /user-management-service {
   #     proxy_pass http://101.35.44.70:8088/user-management-service; #这里的端口记得改成项目对应的哦
    proxy_pass https://域名:8443/user-management-service;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;
}

检查nginx配置,并重启:

docker exec nginx nginx -t
docker exec nginx nginx -s reload

打开浏览器输入https://域名/接口,发现可以正常访问了

备注:因为将443映射成了8443,80映射成了8088,需要去云服务器控制台防火墙开放8443和8088两个端口。

支持wss协议

前端使用了stompJs进行wss连接,默认的nginx不支持wss连接,需要nginx反向代理。

利用nginx代理wss的通讯原理及流程:

  1. 客户端发起wss连接连到nginx
  2. nginx将wss协议的数据转换成ws协议数据并转发到Workerman的websocket协议端口
  3. Workerman收到数据后做业务逻辑处理
  4. Workerman给客户端发送消息时,则是相反的过程,数据经过nginx/转换成wss协议然后发给客户端

编辑default.conf,添加如下内容:

location /user-management-service/websocket {
	proxy_pass https://域名:端口/user-management-service/websocket;        #通过配置端口指向部署websocket的项目
        proxy_http_version 1.1;    
        proxy_set_header Upgrade $http_upgrade;    
        proxy_set_header Connection "Upgrade";    
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
}

stompJs操作如下:

stompConnect (url, success, fail) {
      // url格式为:https://域名:端口/user-management-service/websocket
      this.websocket = new SockJS(url)
      // 获取STOMP子协议的客户端对象
      this.stompClient = Stomp.over(this.websocket)

      this.stompClient.debug = false
      this.stompClient.heartbeat.outgoing = 5000 // 前端对后台连接心跳监控间隔
      this.stompClient.heartbeat.incoming = 0 // 后台对前端心跳监控,若为0则不进行心跳监控

      const headers = {
        Authorization: `Bearer ${store.getters['user/token']}`
      }

      // 向服务器发起websocket连接
      this.stompClient.connect(
        headers, // 此处注意更换自己的用户名,最好以参数形式带入
        frame => {
          console.log('链接成功!')
          success({ frame: frame, stompClient: this.stompClient })
        },
        // 第一次连接失败和连接后断开连接都会调用这个函数 此处调用重连
        err => {
          console.error(err)
          fail(err)
          setTimeout(() => {
            this.stompInit(success, fail, url)
          }, 1000)
        }
      )
}

配置完成后,重启nginx,访问发现wss可以正常访问了,如下图: image.png