ssl证书
申请免费的ssl证书
腾讯云免费的证书只能绑定域名。因为我之前已经购买了域名,又不想花钱,所以申请了腾讯云一年的免费证书。还有,购买的域名需要绑定到对应的云服务器上,并进行域名解析,这样nginx配置后,才能使用域名访问对应的网站。如下图:
配置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证书,下载位置如下图:
切换到配置文件所在目录:
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://域名访问对应网站,配置成功的话,可以看到如下图的情况:
但是访问后端接口,会无法访问,并提示如下错误:
# Mixed Content:'xxx' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'xxx'
是因为前端项目访问后端接口仍然使用的是http协议。需要将后端项目也改成https协议。
springboot项目配置ssl证书
springboot项目默认使用了tomcat服务器,所以需要前往腾讯云下载对应tomcat的ssl证书。如下图:
配置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的通讯原理及流程:
- 客户端发起wss连接连到nginx
- nginx将wss协议的数据转换成ws协议数据并转发到Workerman的websocket协议端口
- Workerman收到数据后做业务逻辑处理
- 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可以正常访问了,如下图: