## 起因
事情起因是我所购买的建站机,不允许用于代理和使用反代,这样我就没有了使用nginx进行反代的机会。
想在不使用反代的情况下开启ssl,需要自行拉取halo源码并进行一些修改。修改方式有两种。
- 对自带的`jetty`进行配置
- 使用`tomcat`替换自带的`jetty`,对tomcat进行配置
## Tomcat
使用tomcat需要在`build.gradle`的dependencies中添加以下依赖
> compile group: "org.apache.tomcat.embed", name: "tomcat-embed-core", version: "9.0.39"
再添加一个文件,文件名随意,这里我起的名是`TomcatSslConfiguration.java`。
```java
package run.halo.app.config;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties
public class TomcatSslConfiguration {
@Value("${server.port}")
private int https;
@Value("${server.ssl.port}")
private int http;
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint constraint = new SecurityConstraint();
constraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
// 全路径重定向到https
collection.addPattern("/*");
constraint.addCollection(collection);
context.addConstraint(constraint);
}
};
tomcat.addAdditionalTomcatConnectors(httpConnector());
return tomcat;
}
@Bean
public Connector httpConnector() {
if (http == 0) {
http = 8090;
}
if (https == 0) {
https = 8443;
}
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
// 设置用什么方案接收请求
connector.setScheme("http");
// 设置要监听的端口号
connector.setPort(http);
// 开启http重定向到https
connector.setSecure(false);
// 重定向到哪个端口
connector.setRedirectPort(https);
return connector;
}
}
```
然后使用`Tasks > build > build`进行编译,虽然会有过时待删除的警告,但在`build > lib`文件夹中能看到编译出的jar包。
然后去下载适用于tomcat的证书文件,推荐将证书文件放在`.halo`文件夹下,部署的时候在`.halo/application.yaml`中添加以下配置。
```yaml
server:
# https端口
port: 443
ssl:
# http端口
port: 80
key-store: .halo/证书文件
key-store-password: 证书密码
keyStoreType: PKCS12
```
配置完即可启动自己编译出的halo检验成果。以上操作相当于直接往SpringBoot中塞了一个tomcat,用来替换原来的web服务器,并在tomcat中进行ssl相关的配置。
### 文章引用
[Spring Boot配置ssl证书启用HTTPS协议](https://cloud.tencent.com/developer/article/1515468)
[springboot配置ssl证书](https://www.cnblogs.com/TheoryDance/p/11180023.html)
[Https系列之三:让服务器同时支持http、https,基于spring boot](https://www.cnblogs.com/garyyan/p/7600322.html)
<br/>
## Jetty
halo使用的SpringBoot,默认的容器是`Jetty`,不需要额外导入依赖,仅需添加一个配置类。
文件名随意,这里我起名为`JettySslConfiguration.java`。
```java
package run.halo.app.config;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
@Slf4j
@Configuration
@EnableConfigurationProperties
public class JettySslConfiguration extends AbstractConfiguration implements
WebServerFactoryCustomizer<JettyServletWebServerFactory> {
@Value("${server.port}")
private int https;
@Value("${server.ssl.port}")
private int http;
@Value("${jetty.connect.maxThreads}")
private int maxThread;
@Value("${jetty.connect.minThreads}")
private int minThread;
@Value("${jetty.connect.idleTimeout}")
private int idleTimeout;
@Override
public void configure(WebAppContext context) throws Exception {
Constraint constraint = new Constraint();
constraint.setDataConstraint(Constraint.DC_CONFIDENTIAL);
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec("/*");
mapping.setConstraint(constraint);
ConstraintSecurityHandler handler = new ConstraintSecurityHandler();
handler.addConstraintMapping(mapping);
context.setSecurityHandler(handler);
}
@Override
public void customize(JettyServletWebServerFactory factory) {
factory.setConfigurations(Collections.singleton(this));
factory.addServerCustomizers(
server -> {
// 配置线程池
threadPool(server);
HttpConfiguration httpsConfiguration = new HttpConfiguration();
httpsConfiguration.setSecurePort(https);
httpsConfiguration.setSecureScheme("https");
ServerConnector connector = new ServerConnector(server);
connector.addConnectionFactory(new HttpConnectionFactory(httpsConfiguration));
connector.setPort(http);
server.addConnector(connector);
}
);
}
private void threadPool(Server server) {
// 线程池
final QueuedThreadPool threadPool = server.getBean(QueuedThreadPool.class);
//默认最大线程连接数200
threadPool.setMaxThreads(maxThread);
//默认最小线程连接数8
threadPool.setMinThreads(minThread);
//默认线程最大空闲时间60000ms
threadPool.setIdleTimeout(idleTimeout);
}
}
```
在不配置`threadPool`的情况下,部署配置与tomcat的相同,如果配置了`threadPool`,则还需要修改`application.yaml`,在编译前/运行前添加以下配置。
```yaml
jetty:
connect:
# 最大线程数
maxThreads: 150
# 最小线程数
minThreads: 10
# 线程最大空闲时间
idleTimeout: 30000
```
<br/>
### 文章引用
[Springboot以Jetty为容器实现http重定向到https](https://zhuanlan.zhihu.com/p/137666602)
[springboot使用tomcat或jetty开通http,https端口](https://blog.csdn.net/ming19951224/article/details/85135451)
[学习,记录,整理] halo在不使用nginx进行反代的情况下开启ssl