Ubuntu 服务器部署 Tomcat 并配置 SSL/TLS 证书
本文目录
- 准备
- 登陆云服务器
- 安装 Java
- 下载 tomcat 包
- 配置防火墙
- 浏览器访问 Tomcat 默认页面
- 以服务的形式运行 Tomcat
- 创建 Tomcat 用户和组
- 创建 systemd 服务文件
- 启动 tomcat 服务
- Tomcat webapps 文件目录
- 部署一个静态网站
- tomcat 的配置文件
- 将域名解析到服务器
- Tomcat 配置 SSL/TLS 证书
- 获取 SSL/TLS 证书
- Tomcat 配置 SSL/TLS 证书,实现 HTTPS,并启用 HTTP/2.0
- 配置 server.xml 文件,使用 keystore.jks 文件
- 解决无法监听 443 端口的问题
- 配置 server.xml 文件,使用证书文件
- apache2 反向代理到 tomcat
- 安装 apache2
- 编辑 apache2 配置文件
- 证书过期更新
准备
- 有一台云服务器。
- 云服务器安装 Ubuntu 操作系统(或者是其他 Linux 操作系统的发行版,本文的演示使用 Ubuntu 系统)。
- 熟悉 Linux 命令行操作。
- 能够远程云服务器。推荐使用 SSH 进行远程,参见 SSH 远程连接。
登陆云服务器
ssh 使用私钥登陆到服务器。
ssh -i /path/to/id_rsa ubuntu@server_IP_address
安装 Java
运行 tomcat 需要 Java 的环境。首先检查 Java 是否安装。java --version
ubuntu@VM-0-17-ubuntu:~$ java --version
Command 'java' not found, but can be installed with:
sudo apt install openjdk-17-jre-headless # version 17.0.12+7-1ubuntu2~24.04, or
sudo apt install openjdk-21-jre-headless # version 21.0.4+7-1ubuntu2~24.04
sudo apt install default-jre # version 2:1.17-75
sudo apt install openjdk-11-jre-headless # version 11.0.24+8-1ubuntu3~24.04.1
sudo apt install openjdk-8-jre-headless # version 8u422-b05-1~24.04
sudo apt install openjdk-19-jre-headless # version 19.0.2+7-4
sudo apt install openjdk-20-jre-headless # version 20.0.2+9-1
sudo apt install openjdk-22-jre-headless # version 22~22ea-1
JDK (Java Development Kit) 包含了Java编译器和其他开发工具,而JRE (Java Runtime Environment) 则包含了运行Java程序所需的运行时环境。对于大多数Tomcat部署,只需安装JRE即可,因为Tomcat主要用于运行Java Web应用程序,而不是编译Java源代码。
安装 JRE 可以选择使用上面的命令 sudo apt install default-jre
,或者根据需要自行选择版本。
安装完成后,输入 java --version
验证安装:
ubuntu@VM-0-17-ubuntu:~$ java --version
openjdk 21.0.5 2024-10-15
OpenJDK Runtime Environment (build 21.0.5+11-Ubuntu-1ubuntu124.04)
OpenJDK 64-Bit Server VM (build 21.0.5+11-Ubuntu-1ubuntu124.04, mixed mode, sharing)
如果想要查看 Java 的安装路径可以使用以下命令:
ubuntu@VM-0-17-ubuntu:~$ which java
/usr/bin/java
ubuntu@VM-0-17-ubuntu:~$ readlink -f /usr/bin/java
/usr/lib/jvm/java-21-openjdk-amd64/bin/java
想要手动配置环境变量的话,可以根据安装路径来手动配置环境变量。一般情况下,安装后会自动配置环境变量。如果验证安装时,发现没有打印 java 版本号相关信息,可能就是环境变量没有配置的问题。
配置环境变量(不需要的跳过此步):
Linux 系统级环境变量的配置文件在 /etc/environment
,使用 vim 进行编辑(vim 的教程网上有很多)。
sudo vim /etc/environment
在 /etc/environment
文件中添加以下内容:注意修改真实的安装路径。注意文件原来的系统环境变量要放在最后一行,并把 :$JAVA_HOME/bin
放在 PATH 末尾。
JAVA_HOME="/usr/lib/jvm/java-21-openjdk-amd64"
CLASSPATH="$JAVA_HOME/lib"
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:$JAVA_HOME/bin"
保存退出 vim 使用 :wq
source /etc/environment
重新加载环境变量。
验证环境变量的配置:
echo $JAVA_HOME
echo $CLASSPATH
echo $PATH
root@VM-0-17-ubuntu:/opt/tomcat/bin# echo $JAVA_HOME
/usr/lib/jvm/java-21-openjdk-amd64
root@VM-0-17-ubuntu:/opt/tomcat/bin# echo $CLASSPATH
/usr/lib/jvm/java-21-openjdk-amd64/lib
root@VM-0-17-ubuntu:/opt/tomcat/bin# echo $PATH
/usr/lib/jvm/java-21-openjdk-amd64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
下载 tomcat 包
下载 Tomcat.tar.gz 包。到 Tomcat 官网 找到对应 Tomcat 版本的下载链接。截至写这篇文章(2024年11月27日)为止,Tomcat 的最新版本是 11 (alpha) 测试版,稳定版是 Tomcat 10 。
我这里下载的版本是 Tomcat 10.1.33,根据需要自行选择版本。
为了后续方便操作,先提升为 root 用户。
sudo -i
下载 tomcat 包:wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.33/bin/apache-tomcat-10.1.33.tar.gz
注意下载链接以后可能会失效,不要直接复制这里,下载链接自行去官网找想要的版本。
root@VM-0-17-ubuntu:/home/ubuntu# wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.33/bin/apache-tomcat-10.1.33.tar.gz
--2024-11-27 16:13:11-- https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.33/bin/apache-tomcat-10.1.33.tar.gz
Resolving dlcdn.apache.org (dlcdn.apache.org)... 151.101.2.132, 2a04:4e42::644
Connecting to dlcdn.apache.org (dlcdn.apache.org)|151.101.2.132|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13678161 (13M) [application/x-gzip]
Saving to: ‘apache-tomcat-10.1.33.tar.gz’apache-tomcat-10.1.33.tar.gz 100%[===============================================>] 13.04M 45.3MB/s in 0.3s2024-11-27 16:13:12 (45.3 MB/s) - ‘apache-tomcat-10.1.33.tar.gz’ saved [13678161/13678161]root@VM-0-17-ubuntu:/home/ubuntu# ls
apache-tomcat-10.1.33.tar.gz
解压缩:tar -xzvf apache-tomcat-10.1.33.tar.gz
root@VM-0-17-ubuntu:/home/ubuntu# tar -xzvf apache-tomcat-10.1.33.tar.gz
apache-tomcat-10.1.33/conf/
apache-tomcat-10.1.33/conf/catalina.policy
apache-tomcat-10.1.33/conf/catalina.properties
apache-tomcat-10.1.33/conf/context.xml
... ...
... ...root@VM-0-17-ubuntu:/home/ubuntu# ls
apache-tomcat-10.1.33 apache-tomcat-10.1.33.tar.gz
复制到 /opt/tomcat 下:cd /opt
+ mkdir tomcat
+ cp -r /home/ubuntu/apache-tomcat-10.1.33/* ./tomcat
cd /opt
root@VM-0-17-ubuntu:/opt# mkdir tomcat
root@VM-0-17-ubuntu:/opt# cp -r /home/ubuntu/apache-tomcat-10.1.33/* ./tomcat
root@VM-0-17-ubuntu:/opt# ls -l tomcat
total 152
drwxr-x--- 2 root root 4096 Nov 27 16:29 bin
-rw-r----- 1 root root 21039 Nov 27 16:29 BUILDING.txt
drwx------ 2 root root 4096 Nov 27 16:29 conf
-rw-r----- 1 root root 6166 Nov 27 16:29 CONTRIBUTING.md
drwxr-x--- 2 root root 4096 Nov 27 16:29 lib
-rw-r----- 1 root root 60393 Nov 27 16:29 LICENSE
drwxr-x--- 2 root root 4096 Nov 27 16:29 logs
-rw-r----- 1 root root 2333 Nov 27 16:29 NOTICE
-rw-r----- 1 root root 3298 Nov 27 16:29 README.md
-rw-r----- 1 root root 6776 Nov 27 16:29 RELEASE-NOTES
-rw-r----- 1 root root 16109 Nov 27 16:29 RUNNING.txt
drwxr-x--- 2 root root 4096 Nov 27 16:29 temp
drwxr-x--- 7 root root 4096 Nov 27 16:29 webapps
drwxr-x--- 2 root root 4096 Nov 27 16:29 work
启动 tomcat:
root@VM-0-17-ubuntu:/opt# cd tomcat/bin
root@VM-0-17-ubuntu:/opt/tomcat/bin# ls
bootstrap.jar commons-daemon.jar digest.sh setclasspath.sh tomcat-native.tar.gz
catalina.bat commons-daemon-native.tar.gz makebase.bat shutdown.bat tool-wrapper.bat
catalina.sh configtest.bat makebase.sh shutdown.sh tool-wrapper.sh
catalina-tasks.xml configtest.sh migrate.bat startup.bat version.bat
ciphers.bat daemon.sh migrate.sh startup.sh version.sh
ciphers.sh digest.bat setclasspath.bat tomcat-juli.jar
tomcat/bin
目录下有个 startup.sh
是一个启动脚本文件。这个脚本会设置必要的环境变量,并调用Tomcat的启动类来启动服务。
执行启动脚本:./startup.sh
root@VM-0-17-ubuntu:/opt/tomcat/bin# ./startup.sh
Using CATALINA_BASE: /opt/tomcat
Using CATALINA_HOME: /opt/tomcat
Using CATALINA_TMPDIR: /opt/tomcat/temp
Using JRE_HOME: /usr
Using CLASSPATH: /opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Tomcat started.
运行 startup.sh
脚本时,它会首先设置一些环境变量,如 CATALINA_HOME
和 CATALINA_BASE
等,这些变量用于指定 Tomcat 的安装目录和工作目录。接着,脚本会调用 catalina.sh
脚本,该脚本是 Tomcat 启动的核心。
在 catalina.sh
脚本中,会调用 org.apache.catalina.startup.Bootstrap
类的 main
方法。这是 Tomcat 启动的入口点。
在 main
方法中,会进行初始化操作,包括创建类加载器、加载 Tomcat 的配置文件等。
Bootstrap
类的 main
方法会调用 init
方法来初始化 Tomcat 所需的类加载器,并设置当前线程的上下文类加载器。
接着,会调用 load
方法来加载 Tomcat 的配置文件,并初始化容器组件。
在完成初始化操作后,Bootstrap
类的 main
方法会调用 start
方法来启动 Tomcat 服务。
Tomcat 服务启动后,会监听指定的端口号(如8080),准备接受客户端的请求。
配置防火墙
Tomcat 在服务器启动后,想要在本地访问 tomcat 的默认页面,要配置防火墙。参见 Linux: iptables && ufw 配置防火墙规则 。Ubuntu 系统内的防火墙要放行 8080 端口的 TCP 流量,服务器提供商的控制台界面的防火墙也要放行 8080 TCP 的流量。最好也把 443 端口的 TCP 流量也放行了,后面配置好 HTTPS 后就不用再配置防火墙了。
浏览器访问 Tomcat 默认页面
配置好防火墙以后,在本地的浏览器输入 http://IP_address:8080
就可以访问到 Tomcat 的默认页面了,IP_address
对应你服务器的公网 IP 地址:
看到以上页面说明你的 Tomcat 部署已经初步成功了。
以服务的形式运行 Tomcat
首先关闭 tomcat 服务:cd /opt/tomcat/bin
+ ./shutdown.sh
进入到 /opt/tomcat/bin
目录,执行关闭脚本。
以上 启动 / 关闭 Tomcat 使用的是 tomcat/bin/startup.sh | shutdown.sh
启动 / 关闭 脚本,我们总不能每次启动 Tomcat 都要运行这个脚本,所以要以一个服务的形式运行 Tomcat 。这里的服务指的就是一种运行在操作系统(Linux)后台的守护进程(daemon),这些所谓的服务由systemd管理,它们负责执行系统所需的各种任务。
Windows 系统上也有这种类似的服务:
创建 Tomcat 用户和组
为了安全起见,我们要创建专门的 tomcat 用户和组来运行 tomcat。
以 root 的身份运行 tomcat 也是可以的,但是会存在安全风险。
因为 root 用户是系统的管理员用户,有着对各种系统文件的访问权限。
以 root 用户身份运行应用程序(包括 Tomcat)意味着该应用程序拥有对整个系统的完全访问权限。
如果 Tomcat 或其中的某个 Web 应用出现安全漏洞,攻击者可以利用该漏洞获得对系统的完全控制权限。
这可能导致:
-
系统篡改:攻击者可以访问和修改系统的核心文件,甚至安装恶意软件或后门。
-
数据泄露:敏感信息(如数据库凭证、用户数据等)可能被泄露或窃取。
-
拒绝服务攻击:攻击者可以消耗系统资源,导致服务无法正常运行。
防止 root 用户滥用的最佳做法是遵循 最小权限原则(Principle of Least Privilege)。即让每个进程或服务仅获得它执行任务所需的最小权限,避免为应用程序提供多余的特权。
命令:
sudo -igroupadd tomcatuseradd -s /bin/false -g tomcat -d /opt/tomcat tomcatchown -R tomcat:tomcat /opt/tomcat
命令解释:
-
groupadd tomcat
添加一个名为 tomcat 的组。 -
useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat
-s
参数用于指定该用户的默认 shell。/bin/false
是一种常用的做法,它表示该用户无法登录系统,因为/bin/false
会立即退出并返回一个失败的状态。这是为了防止 Tomcat 用户通过 SSH 或其他方式直接登录到服务器。设置为/bin/false
后,Tomcat 用户只能作为服务运行,而不能以交互式的方式登录到系统。-g
参数指定新用户的主用户组。tomcat
表示新用户将加入名为tomcat
的组。在创建 Tomcat 服务时,通常会为其创建一个专用的用户和组,用来确保 Tomcat 服务运行时的权限是受限的。通过将 Tomcat 用户加入到同名的tomcat
组,确保它对 Tomcat 文件夹(通常位于/opt/tomcat
)有适当的权限。-d
参数指定用户的主目录。/opt/tomcat
表示 Tomcat 用户的主目录将被设置为/opt/tomcat
。通常情况下,Tomcat 的安装路径是/opt/tomcat
或其他类似的路径,目的是将 Tomcat 文件存放在该目录下。为 Tomcat 用户设置主目录为此路径,并且将该目录的权限授予该用户,使得 Tomcat 可以访问和管理其文件。- 最后,
tomcat
是要创建的用户的用户名。也就是说,命令会创建一个名为tomcat
的用户。
-
chown -R tomcat:tomcat /opt/tomcat
chown
change owner 改变文件或目录的拥有者(user)和所属组(group)的命令。-R
是chown
命令的一个选项,表示 “递归”(recursive)。它的作用是让chown
命令不仅改变指定目录本身的所有者和组,还会递归地改变该目录下所有子目录和文件的拥有者和组。tomcat:tomcat
- 前面的是目标用户(user),即指定的文件或目录的新拥有者(owner)。
- 后面的是目标组(group),即指定的文件或目录的新所属组(group)。
- 在此命令中,
tomcat:tomcat
意味着将/opt/tomcat
目录及其所有子目录和文件的拥有者和所属组都更改为tomcat
用户和tomcat
组。
root@VM-0-17-ubuntu:/opt/tomcat/bin# groupadd tomcat
root@VM-0-17-ubuntu:/opt/tomcat/bin# useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat
root@VM-0-17-ubuntu:/opt/tomcat/bin# chown -R tomcat:tomcat /opt/tomcat
创建 systemd 服务文件
vim /etc/systemd/system/tomcat.service
使用 vim 创建 tomcat.service
文件。
编辑内容如下:
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target[Service]
Type=forking
Environment=JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh
User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always[Install]
WantedBy=multi-user.target
service 文件配置解释:
After=network.target
指定服务的启动顺序。表示 Tomcat 服务将在网络服务启动后再启动。network.target 是指系统的网络服务,通常意味着网络接口已经准备好,能够提供网络功能。因此,Tomcat 会在网络正常运行后才开始启动,以确保 Tomcat 可以正常访问网络。Type=forking
指定服务的启动类型。表示 Tomcat 启动时会创建一个子进程,并且在主进程退出时认为服务已经成功启动。这通常适用于像 Tomcat 这样的服务,它会在启动时创建一个子进程并返回控制。forking 类型的服务通常会启动一个后台进程,而系统认为主进程启动成功后就可以继续执行其他操作。如果 Tomcat 使用的是前台模式,则应使用 Type=simple,但 forking 是 Tomcat 的标准启动方式。Environment
是环境变量。其中JAVA_HOME
根据 Java 的实际安装路径进行更改。Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
设置 Tomcat 的 PID 文件路径。CATALINA_PID
环境变量指定 Tomcat 进程的 PID(进程 ID)文件路径。Tomcat 会将它的进程 ID 写入这个文件,用于后续的进程管理(如停止 Tomcat 时查找该 PID)。CATALINA_HOME
设置 Tomcat 的安装目录。CATALINA_BASE
设置 Tomcat 的基础目录。UMask=0007
设置文件权限掩码。用来设置新创建文件或目录的默认权限。0007
表示文件的权限是rwxr-----
,即文件的所有者可以读、写、执行,组成员可以读取和执行,但其他用户没有任何权限。这是为了确保只有tomcat
用户和tomcat
组能够访问 Tomcat 相关文件。RestartSec=10
设置服务崩溃后重新启动的延迟时间。指定了服务崩溃后等待 10 秒钟再重启。这是为了避免系统在服务崩溃时立即重启,给系统一些时间来恢复,避免频繁重启带来的资源消耗。Restart=always
设置服务崩溃后的重启策略。表示如果 Tomcat 服务停止(无论是正常停止还是崩溃),systemd
都会自动重启服务。这适用于需要持续运行的服务,确保 Tomcat 进程始终在线。WantedBy=multi-user.target
指定服务在启动时应该与哪个目标(target)关联。multi-user.target
是一个systemd
目标,表示系统处于多用户模式下,通常是在没有图形界面的服务器上。当你运行systemctl enable tomcat
时,Tomcat 会被配置为在系统进入multi-user.target
时自动启动,即在系统启动并进入多用户模式时,Tomcat 会自动启动。
编辑完成 service 文件以后,退出 vim 并保存。
启动 tomcat 服务
命令 systemctl daemon-reload
重新加载 systemd 配置,以便它能识别新创建的 tomcat.service
文件。
启动 tomcat 服务:systemctl start tomcat
。
如果需要重启:systemctl restart tomcat
。
检查 Tomcat 服务的状态:systemctl status tomcat
。
root@VM-0-17-ubuntu:/etc/systemd/system# systemctl status tomcat
● tomcat.service - Apache Tomcat Web Application ContainerLoaded: loaded (/etc/systemd/system/tomcat.service; disabled; preset: enabled)Active: active (running) since Wed 2024-11-27 19:40:03 CST; 9s agoProcess: 642898 ExecStart=/opt/tomcat/bin/startup.sh (code=exited, status=0/SUCCESS)Main PID: 642905 (java)Tasks: 35 (limit: 4307)Memory: 104.2M (peak: 104.7M)CPU: 3.768sCGroup: /system.slice/tomcat.service└─642905 /usr/lib/jvm/java-21-openjdk-amd64/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/lo>Nov 27 19:40:03 VM-0-17-ubuntu systemd[1]: Starting tomcat.service - Apache Tomcat Web Application Container...
Nov 27 19:40:03 VM-0-17-ubuntu startup.sh[642898]: Tomcat started.
Nov 27 19:40:03 VM-0-17-ubuntu systemd[1]: Started tomcat.service - Apache Tomcat Web Application Container.
lines 1-14/14 (END)
这时在本地浏览器中检查一下能否访问,http://IP_address:8080
,能够看到 tomcat 默认页面说明服务启动成功。
执行命令 systemctl enable tomcat
希望 Tomcat 在系统启动时自动启动。
systemctl stop tomcat
停止 tomcat 服务。
journalctl -u tomcat
查看 tomcat 的日志。
journalctl -u tomcat -f
查看 tomcat 的实时日志。
journalctl -u tomcat -n 100
查看近 100 条日志。
journalctl -u tomcat --since today
查看今天的日志。
journalctl -u tomcat --since "2024-11-01" --until "2024-11-10"
查看指定时间段的日志。
journalctl -u tomcat | grep "ERROR"
查看错误的日志。 |
管道将前面一条命令的输出作为参数传给后面一条命令,grep
筛选出带有 “ERROR” 的记录。
root@VM-0-17-ubuntu:/etc/systemd/system# systemctl enable tomcat
Created symlink /etc/systemd/system/multi-user.target.wants/tomcat.service → /etc/systemd/system/tomcat.service.
root@VM-0-17-ubuntu:/etc/systemd/system# systemctl status tomcat
● tomcat.service - Apache Tomcat Web Application ContainerLoaded: loaded (/etc/systemd/system/tomcat.service; enabled; preset: enabled)Active: active (running) since Wed 2024-11-27 19:40:03 CST; 5min agoMain PID: 642905 (java)Tasks: 35 (limit: 4307)Memory: 111.1M (peak: 121.3M)CPU: 5.504sCGroup: /system.slice/tomcat.service└─642905 /usr/lib/jvm/java-21-openjdk-amd64/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/lo>Nov 27 19:40:03 VM-0-17-ubuntu systemd[1]: Starting tomcat.service - Apache Tomcat Web Application Container...
Nov 27 19:40:03 VM-0-17-ubuntu startup.sh[642898]: Tomcat started.
Nov 27 19:40:03 VM-0-17-ubuntu systemd[1]: Started tomcat.service - Apache Tomcat Web Application Container.
lines 1-13/13 (END)
至此,tomcat 的基本部署已经完成。
Tomcat webapps 文件目录
root@VM-0-17-ubuntu:/opt/tomcat/webapps# ls
docs examples host-manager manager ROOT
/opt/tomcat/webapps
是 Apache Tomcat 服务器的一个关键目录,用于存放和管理 Web 应用程序。
/opt/tomcat/webapps/
├── app1/
│ ├── WEB-INF/
│ │ ├── classes/ # Java 编译后的类文件
│ │ └── lib/ # 应用所依赖的 jar 包
│ ├── index.html # 主页 HTML 文件
│ └── ... # 其他资源
├── app2/
│ ├── WEB-INF/
│ │ ├── classes/ # Java 编译后的类文件
│ │ └── lib/ # 应用所依赖的 jar 包
│ ├── index.jsp # 主页 JSP 文件
│ └── ... # 其他资源
├── ROOT/ # 默认 Web 应用
│ ├── index.jsp
│ ├── ... # 默认的 Web 应用
└── ...
如果你希望将一个静态的网站部署到 tomcat,那么你只需要将所有的静态网站资源文件复制到 tomcat webapps 下的一个文件夹中。
部署一个静态网站
首先你的本地电脑上已经做好了一个静态网站。然后使用 scp 命令将静态网站所有的资源复制到服务器 /opt/tomcat/webapps/example
下:
创建一个 example 文件夹:
root@VM-0-17-ubuntu:/opt/tomcat/webapps# mkdir example
root@VM-0-17-ubuntu:/opt/tomcat/webapps# ls
docs example examples host-manager manager ROOT
root@VM-0-17-ubuntu:/opt/tomcat/webapps#
scp -i "/path/to/your/private_key/id_rsa" -r /path/to/your/web_resources/* ubuntu@IP_address_of_server:/opt/tomcat/webapps/example/
scp
使用 ssh 协议来进行文件传输。-i
指定私钥文件的路径。-r
递归复制:所有文件及子文件。ubuntu@IP_address_of_server
用户名 ubuntu,@ 服务器 IP 地址。:
冒号加目标路径。
/d/public$ scp -i "/d/.ssh/my_rsa" -r ./* ubuntu@xxx.xxx.xxx.xxx:/opt/tomcat/webapps/example/
Enter passphrase for key '/d/.ssh/my_rsa':
scp: remote mkdir "/opt/tomcat/webapps/example/": Permission denied
上面的运行结果来看复制失败了,因为 /opt/tomcat/webapps/example/
是以 root 权限创建的文件夹,而 ubuntu 用户并没有权限来访问这个文件夹。可以先复制到 ubuntu 用户的某个地方,然后再复制到 example
目录下:
exit
命令退出之前 sudo -i
进入的 root 管理模式。
cd /home/ubuntu/
进入到 ubuntu 用户的目录下,mkdir example
创建文件夹。
再次使用 scp 命令进行复制:
/d/public$ scp -i "/d/.ssh/my_rsa" -r ./* ubuntu@xxx.xxx.xxx.xxx:/home/ubuntu/example/
Enter passphrase for key '/d/.ssh/my_rsa':
1.json 100% 736 2.8KB/s 00:00
hello-world.json 100% 3835 15.1KB/s 00:00
blog-author.json 100% 974 4.0KB/s 00:00
categories.json 100% 2 0.0KB/s 00:00
... ...
... ...
然后在服务器使用 cp 命令复制到 /opt/tomcat/webapps/example/
下:
ubuntu@VM-0-17-ubuntu:~/example$ sudo -i
root@VM-0-17-ubuntu:~# cp -r /home/ubuntu/example/* /opt/tomcat/webapps/example/
root@VM-0-17-ubuntu:~#
这里,我将我的博客网站所有的静态资源放在了 tomcat 下,那么,在浏览器输入 http://IP_address_of_server:8080/example/
就可以访问我的博客网站了。
tomcat 的配置文件
tomcat 的配置文件在 /opt/tomcat/conf/server.xml
。使用 vim 进行编辑。
找到:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
这里可以指定默认 web 应用。添加:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"><Context path="/" docBase="example" />
docBase="example"
用来指定默认的web应用。这样输入 http://xxx.xxx.xxx.xxx:8080
进行访问时就可以直接访问到 example 下的网站了,而不是 tomcat 的默认应用。
每次修改完配置文件,要重启 tomcat 服务才能生效。systemctl restart tomcat
。
将域名解析到服务器
首先你要有一个域名。
在你的域名供应商界面配置 DNS 解析,添加一条 A 记录(域名到 IPv4 地址),Name 栏填写你的域名,Value 栏填写你的服务器的公网 IP 地址。保存后,要等一段时间解析的记录才能生效,因为这条 A 记录要在 Internet 上传播一段时间,让所有的 DNS 服务器都能接收到这条 A 记录。
当这条 DNS A 记录在 Internet 上广泛传播以后,你在浏览器就可以通过域名来访问你的博客网站了。
在你的域名供应商的 DNS 界面,你也可以指定第三方 DNS 服务器来解析你的域名,这样,你的 DNS A 记录要配置在第三方 DNS 服务器上,而你的域名供应商 DNS 界面,要配置这个第三方 DNS 服务器提供的域名,具体情况下,这个第三方 DNS 服务器会告诉你怎么做。使用第三方 DNS 服务器来进行 DNS 解析,速度会更快一些。
有关 DNS 解析的原理,参见往期的文章 Linux: C语言发起 DNS 查询报文 和 Linux: C语言解析域名 两篇文章。
Tomcat 配置 SSL/TLS 证书
SSL/TLS 就是在 HTTP 协议上实现了加密,让你和服务器之间的通信变得更加安全。
Tomcat 是支持 http/2.0 协议的,但是 http/2.0 协议要求必须使用 SSL/TLS 加密,所以要想使用 h2 协议,首先配置 SSL/TLS 加密。
获取 SSL/TLS 证书
这里使用 certbot 来获取 SSL/TLS 证书。
由于我的博客网站 jackey-song.com 已经配置了一条 A 记录,所以本文演示的这台云服务器配置一个子域名 example,以获取 SSL/TLS 证书。配置子域名使用 A 记录,Name 栏填写 example,Value 栏填写云服务器的公网 IP 地址。
Ubuntu 上安装 certbot:
sudo apt update
sudo apt install certbot
安装成功后,执行 certbot -h
会打印帮助信息,以验证安装是否成功。
临时关闭 tomcat 服务,tomcat 会占用 8080 端口。systemctl stop tomcat
,然后使用命令检查 80 端口是否被占用 netstat -tuln | grep :80
。
进行下一步之前请确保你的域名已经指向了你的服务器,因为 certbot 的操作会验证域名的所有权,检验域名是否指向了云服务器。
执行命令:certbot certonly --standalone -d example.jackey-song.com
这是我服务器的域名,你要替换其中的 example.jackey-song.com
为你的域名。
执行命令后,按照提示输入你的 email 等操作,下面是完整过程:
root@VM-0-17-ubuntu:/opt/tomcat/conf# certbot certonly --standalone -d example.jackey-song.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)(Enter 'c' to cancel): my_email_address@xxx.com- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
Account registered.
Requesting a certificate for example.jackey-song.comSuccessfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.jackey-song.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.jackey-song.com/privkey.pem
This certificate expires on 2025-02-25.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
可以看到证书保存的文件路径:Certificate is saved at: /etc/letsencrypt/live/example.jackey-song.com/fullchain.pem
和 Key is saved at: /etc/letsencrypt/live/example.jackey-song.com/privkey.pem
。
certbot certonly --standalone -d example.jackey-song.com
命令解释:
certonly
参数告诉 Certbot 只执行证书的申请过程,而 不配置 Web 服务器。即,certonly 只会获取证书并将其保存在服务器上,而不会修改任何 Web 服务器配置或自动启用 HTTPS。--standalone
是 Certbot 的一种 验证方法,它允许 Certbot 在没有现有 Web 服务器的情况下验证域名的所有权。此选项启动一个临时的 Web 服务器,并在 80 端口上进行 HTTP 验证。- Certbot 会启动一个临时的 HTTP 服务器监听在 80 端口(或者 443 端口,如果你选择了 HTTPS 验证)。然后,它会向 Let’s Encrypt 提交验证请求,Let’s Encrypt 会尝试通过 HTTP 请求访问你服务器上生成的临时文件来验证你对域名的所有权。所以前面要关闭 tomcat 服务,并确定 80 端口没有被其他进程占用。如果不关闭 tomcat 服务,也可以使用其他命令:
certbot certonly --webroot -w /opt/tomcat/webapps/example -d yourdomain.com
,其中使用--webroot
参数时,Certbot 会将一个临时文件写入指定的 Web 根目录,然后通过 HTTP 请求验证域名。需要指定 -w 参数来告诉 Certbot 的 Web 根目录。根目录在之前 server.xml 配置中,已经指向了 example。如果你配置的是不同的根目录,这里要修改一下。
- Certbot 会启动一个临时的 HTTP 服务器监听在 80 端口(或者 443 端口,如果你选择了 HTTPS 验证)。然后,它会向 Let’s Encrypt 提交验证请求,Let’s Encrypt 会尝试通过 HTTP 请求访问你服务器上生成的临时文件来验证你对域名的所有权。所以前面要关闭 tomcat 服务,并确定 80 端口没有被其他进程占用。如果不关闭 tomcat 服务,也可以使用其他命令:
-d
是指定你要为其申请证书的域名。
Tomcat 配置 SSL/TLS 证书,实现 HTTPS,并启用 HTTP/2.0
首先转换证书为 Java Keystore (JKS) 格式。Tomcat 使用 Java Keystore 来存储 SSL/TLS 证书,所以我们需要将从 Let’s Encrypt 获得的证书(PEM 格式)转换为 JKS 格式。
openssl pkcs12 -export -in /etc/letsencrypt/live/example.jackey-song.com/fullchain.pem -inkey /etc/letsencrypt/live/example.jackey-song.com/privkey.pem -out /etc/letsencrypt/live/example.jackey-song.com/keystore.p12 -name tomcat
该命令用于将 SSL 证书 和 私钥 合并为 PKCS#12 格式的文件,该文件可以包含证书(cert.pem)、私钥(privkey.pem)以及证书链(fullchain.pem)。命令中注意修改你的域名,和实际的证书路径。
-export
参数指定将证书和私钥导出到 PKCS#12 格式文件中。-in
指定包含 证书链(fullchain.pem)的输入文件。-inkey
指定包含 私钥(privkey.pem)的输入文件。私钥是和公钥匹配的密钥,用于加密和解密数据,是 SSL/TLS 通信中的关键部分。-out
指定输出的 PKCS#12 文件 (.p12
) 的路径。-name tomcat
指定在 PKCS#12 文件中的证书别名(Alias)。这个别名用于区分同一 keystore 文件中可能包含的多个证书。-name 参数是给证书设置一个标识符,以便在导入 keystore 时,能够根据该别名引用证书。
执行命令后,提示设置密码,该密码用于保证 keystore.p12 文件的安全,不设置密码直接按回车键:
root@VM-0-17-ubuntu:/opt/tomcat/conf# openssl pkcs12 -export -in /etc/letsencrypt/live/example.jackey-song.com/fullchain.pem -inkey /etc/letsencrypt/live/example.jackey-song.com/privkey.pem -out /etc/letsencrypt/live/example.jackey-song.com/keystore.p12 -name tomcat
Enter Export Password:
Verifying - Enter Export Password:
root@VM-0-17-ubuntu:/opt/tomcat/conf# ls /etc/letsencrypt/live/example.jackey-song.com
cert.pem chain.pem fullchain.pem keystore.p12 privkey.pem README
root@VM-0-17-ubuntu:/opt/tomcat/conf#
然后,将 PKCS12
格式的证书导入到 Java Keystore 中:
命令:keytool -importkeystore -destkeystore /opt/tomcat/conf/keystore.jks -srckeystore /etc/letsencrypt/live/example.jackey-song.com/keystore.p12 -srcstoretype PKCS12 -alias tomcat
参数说明:
-destkeystore /opt/tomcat/conf/keystore.jks
:指定目标 Java Keystore 文件的路径,通常是Tomcat/conf
目录下。-srckeystore /etc/letsencrypt/live/example.jackey-song.com/keystore.p12
:指定刚才生成的 PKCS12 文件。-srcstoretype PKCS12
:指定源文件类型是 PKCS12 格式。
执行该命令,提示输入密码,该密码用来保护 keystore.jks
文件的安全。Enter source keystore password:
后面输入的是 keystore.p12 文件的密码。
root@VM-0-17-ubuntu:/opt/tomcat/conf# keytool -importkeystore -destkeystore /opt/tomcat/conf/keystore.jks -srckeystore /etc/letsencrypt/live/example.jackey-song.com/keystore.p12 -srcstoretype PKCS12 -alias tomcat
Importing keystore /etc/letsencrypt/live/example.jackey-song.com/keystore.p12 to /opt/tomcat/conf/keystore.jks...
Enter destination keystore password:
Re-enter new password:
Enter source keystore password:
root@VM-0-17-ubuntu:/opt/tomcat/conf# ls | grep .jks
keystore.jks
配置 server.xml 文件,使用 keystore.jks 文件
vim server.xml
找到 <Connector port="8080">
这一部分,将其重定向到 443
端口,后面添加支持 SSL/TLS 的内容:
<Connector port="8080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="443"maxParameterCount="1000" /><Connector protocol="org.apache.coyote.http11.Http11NioProtocol"port="443"maxThreads="150"SSLEnabled="true"><SSLHostConfig><Certificate certificateKeystoreFile="/opt/tomcat/conf/keystore.jks"certificateKeystorePassword="changeit"certificateKeyAlias="tomcat"type="RSA" /></SSLHostConfig>
</Connector>
certificateKeystorePassword="changeit"
这里密码要修改为keystore.jks
的保护密码。certificateKeyAlias="tomcat"
这里是指 PKCS#12 文件中的证书别名(Alias)。
检查确定 server.xml 的权限是 tomcat,ls -l /opt/tomcat/conf/server.xml
。如果不是,修改 server.xml 文件的权限:chown tomcat:tomcat /opt/tomcat/conf/server.xml
+ chmod 600 /opt/tomcat/conf/server.xml
。
这里注意,1024 以下的端口号(including 1024),非 root 权限是无法监听的,这里测试的话,先使用 root 用户运行 tomcat 。
在运行 tomcat 之前需要确认之前运行的 tomcat 进程已经关闭,否则可能因曾经运行的 tomcat 正在占用端口而无法监听。
ps aux | grep tomcat
命令查找 tomcat 进程:(ps aux | grep '[t]omcat'
该命令不会显示 grep 行,这里,[t]omcat
是一个正则表达式,它匹配包含 “tomcat” 的行,但因为 grep
命令行中的 “tomcat” 前面没有 t
(实际上是 grep --color=auto tomcat
),所以 grep
自身的行不会被匹配到。注意,这里的 t
是任意的,只是为了确保正则表达式不匹配到 grep
命令本身。你也可以使用其他字符,只要它不出现在你实际要搜索的字符串前面即可。)
root@VM-0-17-ubuntu:/opt/tomcat/conf# ps aux | grep tomcat
root 802473 0.0 0.0 6544 2304 pts/1 S+ 03:54 0:00 grep --color=auto tomcat
上面最后一条是 grep 命令本身自带了 tomcat。如果有其他信息如:
root@VM-0-17-ubuntu:/opt/tomcat/conf# ps aux | grep tomcat
root 782976 0.6 3.4 3560580 127812 pts/1 Sl 02:54 0:05 /usr/lib/jvm/java-21-openjdk-amd64/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED -classpath /opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/opt/tomcat -Dcatalina.home=/opt/tomcat -Djava.io.tmpdir=/opt/tomcat/temp org.apache.catalina.startup.Bootstrap start
root 787013 0.0 0.0 6544 2304 pts/1 S+ 03:07 0:00 grep --color=auto tomcat
则表明有正在运行的 tomcat 进程,这时候可以使用 systemctl stop tomcat
或者 /opt/tomcat/bin/shutdown.sh
来结束 tomcat 进程。亦或者直接使用 kill -9 782976
来杀死指定进程 782976
为指定进程的进程号(PID)。
每次重新启动 tomcat 前,检查端口占用情况使用 netstat -tuln
命令:确定 80 端口或者 443 没有被其他进程占用。netstat -tuln | grep 80
/ netstat -tuln | grep 443
。
root@VM-0-17-ubuntu:/opt/tomcat/conf# netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.54:53 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
udp 0 0 127.0.0.54:53 0.0.0.0:*
udp 0 0 127.0.0.53:53 0.0.0.0:*
udp 0 0 10.0.0.17:68 0.0.0.0:*
udp 0 0 127.0.0.1:323 0.0.0.0:*
udp6 0 0 ::1:323 :::*
确定没有其他进程占用端口,或者曾经运行的 tomcat 进程全部关闭后,以 root 的权限手动启动 tomcat :/opt/tomcat/bin/startup.sh
,这时候查看端口 80 和 443 是否被监听,使用上面提到的命令。如果端口被监听,那么就可以在浏览器中通过域名访问你的网站了。
注意看,本文演示的 tomcat 10.1.33 版本,在配置中并没有指定使用 http/2.0 协议,但是从调试界面来看已经默认支持了 h2 协议了:
如果你做到这里,一切顺利,那么恭喜你,你已经取得了阶段性成果。
如果你无法访问你的网站,尝试配置防火墙放行 TCP:443 端口。iptables -A INPUT -p tcp --dport 443 -j ACCEPT
,之前的文章中也写了如何配置 Linux 防火墙。还要注意服务器供应商的控制台界面,也有个防火墙,也要放行 TCP:443 的流量。
如果运行 tomcat 出现错误,请执行 tail -f /opt/tomcat/logs/catalina.out
查看 tomcat 的日志文件,并查找相关错误信息以及解决方法。
解决无法监听 443 端口的问题
上面启动 tomcat 并不是以一个服务的形式启动,而是使用 root 权限,手动启动。因为 非 root 权限无法监听小于等于 1024 以下的端口,而配置 tomcat.service 文件时,使用 User=tomcat Group=tomcat
的权限来启动 tomcat,这导致 tomcat 没有足够的权限监听 443 端口。
为了解决这个问题,有以下方法:
-
可以修改 tomcat.service 文件,
User=root
以 root 权限来启动 tomcat,但是这样会带来风险,root 权限过大,如果 tomcat 的 web 应用有潜在的 bug ,会导致服务器遭受攻击。所以不推荐这么做。 -
还有一种方法,那就是赋予 Tomcat 绑定绑定到特权端口(<=1024)的权力,使用
setcap
命令:sudo setcap 'cap_net_bind_service=+ep' /usr/lib/jvm/java-21-openjdk-amd64/bin/java
因为 tomcat 使用的是 java 的运行环境,所以要赋予 java 绑定特权端口的权力。这样在以服务的形式启动 tomcat 的时候,就可以绑定 443 端口了。- 移除
java
绑定特权端口的权力,使用命令setcap -r /path/to/java
。 - 查看是否移除:
getcap /path/to/java
。
-
还有一种方法,tomcat 监听 8433 端口,然后使用反向代理。前提是代理具有监听 443 端口的权限,然后反向代理到 tomcat 的 8443 端口。比如 apache2,可以将 SSL/TLS 证书配置到 apache2,tomcat 不处理 https,只运行 http/1.1 ,然后将 apache2 反向代理到 tomcat 。
-
还还还还还还有一种方法,那就是 iptables 将来自443端口的流量转发到Tomcat实际监听的较高端口(例如8443)。这样,Tomcat可以在非特权端口上运行,而外部请求则通过iptables转发到该端口。
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
该命令在NAT(网络地址转换)表的PREROUTING链上添加一条规则。-t nat
:指定要操作的表是NAT表。NAT表主要用于地址转换,包括源地址转换(SNAT)和目的地址转换(DNAT),以及端口重定向等。-A PREROUTING
:表示向PREROUTING链添加(Append)一条规则。PREROUTING链用于处理进入本机之前、且尚未进行路由选择的数据包。-p tcp
:指定要匹配的协议是TCP。这意味着该规则仅适用于TCP协议的数据包。--dport 443
:指定目的端口为443。-j REDIRECT
:指定匹配的数据包应该执行的动作是REDIRECT(重定向)。REDIRECT动作会将数据包重定向到本机的另一个端口上,而不是进行地址转换。--to-port 8443
:指定重定向的目标端口是8443。这意味着所有目的端口为443的TCP数据包都会被重定向到本机的8443端口上。iptables -t nat -L -n
查看 nat 表:root@VM-0-17-ubuntu:/opt/tomcat# iptables -t nat -L -n Chain PREROUTING (policy ACCEPT) target prot opt source destination REDIRECT 6 -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8443
systemctl restart tomcat
重启tomcat。root@VM-0-17-ubuntu:/opt/tomcat# netstat -tuln | grep 443 tcp6 0 0 :::8443 :::* LISTEN
可以看到只有 8443 端口在被监听,但是此时在浏览器仍然能使用 https 协议访问网站。
配置 server.xml 文件,使用证书文件
关于 server.xml 文件的配置:除了使用 keystore.jks 文件,也可以直接使用证书文件进行配置。至于你的 tomcat 是否支持这样做,请到 tomcat 查阅官方文档。
<Connectorprotocol="org.apache.coyote.http11.Http11NioProtocol"port="443"maxThreads="150"SSLEnabled="true"><SSLHostConfig><CertificatecertificateKeyFile="/path/to/privkey.pem"certificateFile="/path/to/cert.pem"certificateChainFile="/path/to/chain.pem"type="RSA"/></SSLHostConfig></Connector>
注意修改真实的证书文件的路径。同时确保 tomcat 用户有足够的权限访问这些文件,因为这些文件在创建的时候都是以 root 身份创建的。
文章到这里基本上算是结束了,下面的内容是使用 apache2 进行反向代理(一开始使用 apache2 会非常简单,所以 apache2 的反向代理放在最后)。
apache2 反向代理到 tomcat
使用 apache2 进行反向代理的话,就不需要 tomcat 配置证书了。cp server.xml server.xml.backup
将已经配置好证书的 server.xml
备份一下为 server.xml.backup
,server.xml 中删掉证书配置的 <Connector ... />
。
安装 apache2
sudo apt update
sudo apt install apache2
启动 apache2 服务
sudo systemctl start apache2
设置 apache2 开机自动启动
sudo systemctl enable apache2
编辑 apache2 配置文件
/etc/apache2/sites-available/my_conf.conf
,这里的配置文件名随意起,配置文件中写入如下内容:
<IfModule mod_ssl.c>
<VirtualHost *:443>ServerAdmin webmaster@localhostServerName example.jackey-song.com# SSL配置开始SSLCertificateFile /etc/letsencrypt/live/example.jackey-song.com/cert.pemSSLCertificateKeyFile /etc/letsencrypt/live/example.jackey-song.com/privkey.pemSSLCertificateChainFile /etc/letsencrypt/live/example.jackey-song.com/chain.pem# 反向代理到 TomcatProxyPreserveHost OnProxyPass / http://127.0.0.1:8080/ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
</IfModule>
保存后退出 vim 。
然后执行 sudo a2ensite /etc/apache2/sites-available/my_conf.conf
启用配置文件。
systemctl reload apache2
systemctl restart apache2
systemctl enable apache2
sudo a2enmod proxy
启用代理模块。
sudo a2enmod proxy_http
sudo a2enmod ssl
启用 SSL。
sudo systemctl restart apache2
重启 apache2 。
由于配置了 apache2 反向代理,所以要移除 iptables
443 到 8443 的重定向。
root@VM-0-17-ubuntu:/etc/apache2/sites-available# iptables -t nat -L PREROUTING -v -n --line-numbers
Chain PREROUTING (policy ACCEPT 3686 packets, 117K bytes)
num pkts bytes target prot opt in out source destination
1 54 3104 REDIRECT 6 -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8443
root@VM-0-17-ubuntu:/etc/apache2/sites-available# iptables -t nat -D PREROUTING 1
这时候,在浏览器通过域名访问网站,访问成功!apache2 反向代理配置成功!
证书过期更新
使用 certbot 会从 Let’s Encrypt 获得免费的证书。在SSL/TLS证书过期前,Certbot能够自动化处理续订和更新过期的证书。Let’s Encrypt颁发的证书通常有效期为90天。经常更换证书就像我们经常更新我们的账号密码一样,是为了安全起见。运行命令 sudo certbot renew --dry-run
,这个命令将模拟续订和更新证书的过程,但不会实际更新证书。它将显示哪些证书将被续订,以及续订过程中可能出现的任何错误。
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -noout -text | grep -A2 "Not After"
该命令用于检查证书的过期日期。
如果想要让证书更新时,自动转换成 keystore.jks 格式,可以写一个 Bash 脚本来检查证书的过期日期,并在必要时执行转换步骤。
本文结束。离开前记得给本文一键三连,这篇文章写了很久,字数为 27000 多字。觉得本文有用的朋友,可以到我博客网站打赏一下博客文章,请我喝杯咖啡吧。
END
相关文章:
Ubuntu 服务器部署 Tomcat 并配置 SSL/TLS 证书
本文目录 准备登陆云服务器安装 Java下载 tomcat 包配置防火墙浏览器访问 Tomcat 默认页面以服务的形式运行 Tomcat创建 Tomcat 用户和组创建 systemd 服务文件启动 tomcat 服务 Tomcat webapps 文件目录部署一个静态网站tomcat 的配置文件 将域名解析到服务器Tomcat 配置 SSL/…...
不间断电源 (UPS) 对现代技术可靠性的影响
在这个技术型世界里,无论是在个人还是商业环境中,电力供应商提供的稳定供电都变得越来越重要。 不间断电源 (UPS) 系统是一种不可或缺的解决方案,可保证终端设备不受干扰地运行,在出现电源问题或故障时让用户继续工作。 这篇文章…...
Android 基础类(01)- Thread类 - readyToRun和threadLoop
一、前言: 在阅读AOSP代码过程中,我们经常会看到Thread子类重写两个方法:readyToRun和threadLoop,不清楚的同学,可能在这儿连调用逻辑都搞不清楚了,因为找不到谁调用了它。我这儿先不去深究Thread内部逻辑…...
【组件封装】uniapp vue3 封装一个自定义下拉刷新组件pullRefresh,带刷新时间和加载动画教程
文章目录 前言一、实现原理二、组件样式和功能设计三、scroll-view 自定义下拉刷新使用回顾相关属性:最终版完整代码: 前言 手把手教你封装一个移动端 自定义下拉刷新组件带更新时间和加载动画(PullRefresh),以uniapp …...
通过 JNI 实现 Java 与 Rust 的 Channel 消息传递
做纯粹的自己。“你要搞清楚自己人生的剧本——不是父母的续集,不是子女的前传,更不是朋友的外篇。对待生命你不妨再大胆一点,因为你好歹要失去它。如果这世上真有奇迹,那只是努力的另一个名字”。 一、crossbeam_channel 参考 cr…...
一起学习Fortran:如何安装Fortran
Fortran(全称Formula Translation,意为“公式翻译”)是一种通用编译命令式编程语言,适用于数值计算和科学计算。Fortran语言最初是由IBM在20世纪50年代为科学和工程应用程序而开发的,第一个Fortran版本——FORTRAN I在…...
社交新零售模式下“2+1 链动模式 S2B2C 商城小程序”的创新实践与发展策略
摘要:随着实体商业与社交网络深度融合,社交新零售蓬勃兴起,“21 链动模式 S2B2C 商城小程序”作为其中创新典范,融合独特激励机制与数字化运营优势,重塑零售生态。本文剖析该模式架构、运作逻辑,探讨其在私…...
【博主推荐】C# Winform 拼图小游戏源码详解(附源码)
文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代,程序开…...
贝叶斯统计的核心思想与基础知识:中英双语
中文版 贝叶斯统计的核心思想与基础知识 贝叶斯统计是以贝叶斯定理为核心,通过将先验知识和观测数据相结合,更新对参数或模型的认知的一种统计方法。它不仅强调概率的频率解释(频率统计学中概率描述事件的长期发生频率)…...
Verilog使用liberty文件中cell单元的demo
Liberty(.lib)文件是用来描述标准单元库中逻辑单元(如门电路、触发器等)的时序和功耗特性的,不是用来直接定义Verilog中的元件。在Verilog设计中,我们通常通过实例化模块(module)来创…...
openssl生成ca证书
常见CA文件夹 1、生成CA钥匙 openssl genrsa -out ./private/cakey.pem 2、生成CA自签名 openssl req -new -x509 -key ./private/cakey.pem -out ./cacert.crt -days 3650 3、生成http服务器私钥 openssl genrsa -out ./data/frontt.project.com.key 2048 4、CA给http服务器…...
OGRE 3D----2. QGRE + QQuickView
将 OGRE(面向对象图形渲染引擎)集成到使用 QQuickView 的 Qt Quick 应用程序中,可以在现代灵活的 UI 框架中提供强大的 3D 渲染功能。本文将指导您如何在 QQuickView 环境中设置 OGRE。 前提条件 在开始之前,请确保您已安装以下内容: Qt(版本 5.15 )OGRE(版本14.2.5)…...
【Java 学习】面向程序的三大特性:封装、继承、多态
引言 1. 封装1.1 什么是封装呢?1.2 访问限定符1.3 使用封装 2. 继承2.1 为什么要有继承?2.2 继承的概念2.3 继承的语法2.4 访问父类成员2.4.1 子类中访问父类成员的变量2.4.2 访问父类的成员方法 2.5 super关键字2.6 子类的构造方法 3. 多态3.1 多态的概…...
Online Judge——【前端项目初始化】Vue-CLI初始化项目、组件库引入
目录 一、创建项目二、前端工程化配置三、引入组件 一、创建项目 输入命令:vue create oj-frontend来到如下界面: 选择Manually select features 选择如下图的组件:注意空格是选择,之后回车即可。 选择3.x版本 继续选择ÿ…...
ASP.NET Web(.Net Framework)POST无法正常接收数据
ASP.NET Web(.Net Framework)POST无法正常接收数据 介绍站点Post和Get如何打断点测试测试代码如下服务器站点Post方法修改原因总结 总结 介绍 这一篇文章主要是讲一下之前搭建的HTTP站点POST无法正常接收数据,如果还不知道怎么搭建HTTP站点的…...
vue安装cypress及其部分用法
安装Cypress 在vue中安装Cypress 1. 安装 Cypress 首先,确保你已经安装了 Cypress。在你的 Vue 项目根目录下运行以下命令: npm install cypress --save-dev2. 打开 Cypress 安装完 Cypress 后,可以通过以下命令打开 Cypress 测试界面&a…...
Web Worker 入门:让前端应用多线程化
引出: 作为前端切图仔,在之前的工作中一直都是写后台,没机会用到web Worker,传统的性能优化web Worker用到的场景也很少,毕竟大量的数据计算一般直接给后端去做就行,轮不到前端来考虑(没遇到类似…...
Vue+Elementui el-tree树只能选择子节点并且支持检索
效果: 只能选择子节点 添加配置添加检索代码 源码: <template><div><el-button size"small" type"primary" clearable :disabled"disabled" click"showSign">危险点评估</el-button>…...
MySQL各种问题的原因及解决方案梳理
背景:由于最近一直在做生产环境和测试环境的切换,遇到了各种各样的MySQL问题,为了后面的开发顺利,梳理一下MySQL的报错及解决方案 问题1、MySQL的链接数超过了本身MySQL内部设置的链接限制 报错信息: // An highlig…...
LeetCode—74. 搜索二维矩阵(中等)
仅供个人学习使用 题目描述: 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true…...
【Redis】Redis介绍
目录 1.Redis是什么? 2. Redis特性 2.1 速度快 2.2 基于键值对的数据结构服务器 2.3 丰富的功能 2.4 简单稳定 2.5 客户端语言多 2.6 持久化 2.7 主从复制 2.8 高可用和分布式 3. Redis使用场景 3.1 缓存(Cache) 3.2 排行榜系统 3.3 计数器应用 3.4 社交网络 …...
Python 3 教程第23篇(模块)
Python3 模块 在前面的几个章节中我们基本上是用 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了。 为此 Python 提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式…...
课题组自主发展了哪些CMAQ模式预报相关的改进技术?
空气污染问题日益受到各级政府以及社会公众的高度重视,从实时的数据监测公布到空气质量数值预报及预报产品的发布,我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…...
七牛云AIGC内容安全方案助力企业合规创新
随着人工智能生成内容(AIGC)技术的飞速发展,内容审核的难度也随之急剧上升。在传统审核场景中,涉及色情、政治、恐怖主义等内容的标准相对清晰明确,但在AIGC的应用场景中,这些界限变得模糊且难以界定。用户可能通过交互性引导AI生成违规内容,为审核工作带来了前所未有的不可预测…...
Vue.js 中的事件处理
在 Vue.js 中,事件处理是用户与应用交互的重要方式。Vue.js 允许开发者以一种声明式的方式来绑定事件监听器,这使得代码更加简洁和易于维护。本文将介绍 Vue.js 中的事件处理,包括常用的事件类型和如何使用它们。 Vue.js 事件基础 在 Vue.j…...
Windows用pm2部署node.js项目
Windows上pm2启动命令不生效 按照常规启动命令应该如下,但是发现不生效 pm2 start npm --name "project-name" -- start具体如下,可以看到状态都是stopped $ pm2 start npm --name "chatgpt-next-web" -- start [PM2] Starting …...
算法【Java】—— 动态规划之路径问题
前言 本文章终点解析第一道题目【不同路径】和最后一道题目【地下城游戏】的动态规划思路,中间几道题目会很快过完,大家如果不熟悉动态规划的思路可以重点看一下这两道题目的解析。 不同路径 https://leetcode.cn/problems/unique-paths 解析…...
DreamFace4.9.0 |AI照片动画师,让照片说话和跳舞
DreamFace是一款有趣的照片动画应用程序,通过AI技术让您的照片唱歌、跳舞甚至说话。只需上传照片并选择歌曲,即可生成动态效果。此外,它还支持图片增强、降噪和高清处理,创建人工智能驱动的头像。无论是让宠物说话还是让朋友唱情歌…...
vue-baidu-map基本使用
vue-baidu-map 是一个基于 Vue.js 的百度地图组件库,它封装了百度地图的 JavaScript API,使得在 Vue 项目中使用百度地图功能更加便捷。下面是如何在 Vue 项目中安装和使用 vue-baidu-map 的步骤: 安装 首先确保你的项目已经集成了 Vue 和 …...
新电脑验机-允许上网,同时禁止windows系统联网自动激活
效果: 重要提示:我虽然得到上图效果,但也不确定是否有坑,不保证商家是否认可。 笔记本电脑七天无理由退货的前提条件是“windows和office未激活”。如何 oobe\bypassnor 绕过开机联网并创建本地账号的方法我就不写了,搜…...
Android 是否支持AB分区
Android 是否支持AB分区 C:\Users\Administrator>adb shell bengal:/ $ su bengal:/ # getprop |grep treble [ro.treble.enabled]: [true] bengal:/ #返回不为空而且为true,那就是支持pt(project treble)分区 进入fastboot模式 adb reboot bootloader查看当前…...
Qt6.8安卓Android开发环境配置
时隔多年,重拾QtCreator下Android开发。发现Qt6下安卓开发环境配置变简单不少!只需三步即可在QtCreator下进行Android开发: 一、使用Qt Mantenance Tool进行Android模块的安装: 如果感觉安装网速较慢,可以查看本人另外…...
JavaSE——类与对象(4)
一、静态变量 1.1为什么要有静态变量 现在有一群小朋友在做游戏,不是有新的小朋友加入,请问如何知道现在共有多少人在完?看这段代码: public class first {public static void main(String[] args) {int count 0;child child1 …...
网络编程中的字节序函数htonl()、htons()、ntohl()和ntohs()
目录 1,网络字节序和主机字节序 2. 函数的具体作用 2.1,htonl(Host to Network Long) 2.2,htons(Host to Network Short) 2.3,ntohl(Network to Host Long) 2.4,ntohs(Network to Host Sho…...
如何在HarmonyOS NEXT中处理页面间的数据传递?
大家好,前两天的Mate70的发布,让人热血沸腾啊,不想错过,自学的小伙伴一起啊,今天分享的学习笔记是关于页面间数据伟递的问题,在HarmonyOS NEXT 5.0 中,页面间的数据传递可以有很多种方式&#x…...
【Code First】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列 …...
Day28 贪心算法 part02
122.买卖股票的最佳时机II 本题解法很巧妙,本题大家可以先自己思考一下然后再看题解,会有惊喜! class Solution {public int maxProfit(int[] prices) {//分析每一天的情况。只要保证今天买,明天卖可以不亏钱,那就是最大的利润。把每一天可以赚钱的机会都不放过,先把能挣…...
JVM_栈详解一
1、栈的存储单位 **栈中存储什么?**, 每个线程都有自己的栈,栈中的数据都是以栈帧(Stack Frame)的格式存在。在这个线程上正在执行的每个方法都各自对应一个栈帧(Stack Frame)。 栈帧是一个内存…...
深入浅出UART驱动开发与调试:从基础调试到虚拟驱动实现
往期内容 本专栏往期内容:Uart子系统 UART串口硬件介绍深入理解TTY体系:设备节点与驱动程序框架详解Linux串口应用编程:从UART到GPS模块及字符设备驱动 解UART 子系统:Linux Kernel 4.9.88 中的核心结构体与设计详解IMX 平台UART驱…...
集成量子光子学(IQP)
IQP 正在成为量子计算的可行替代方案量子源、波导和调制器等领域的研究使这成为可能与 CMOS 技术的兼容意味着工业可扩展性将更加容易 量子光子学的基本组成部分 IQP 系统的基本组成部分包括: 来源(例如腔体中的 QD) 波导定向耦合器&#…...
【代码随想录|贪心算法02】
122.买股票的最佳时机 题目链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii 好巧妙的一道题啊,做之前完全不会想到这种解法。 局部最优:收集每天正利润 全局最优:求得最大利润 这道题只让你返回最大的利润和&…...
CentOS7 使用xtrabackup备份及恢复
安装备份工具 1.安装Percona yum存储库 sudo yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm安装过程中需要按y继续安装 2.启用Percona Server 5.7存储库 sudo percona-release setup ps573、安装percona-xtrabackup-24 sudo yum -y instal…...
【网络安全设备系列】12、态势感知
0x00 定义: 态势感知(Situation Awareness,SA)能够检测出超过20大类的云上安全风险,包括DDoS攻击、暴力破解、Web攻击、后门木马、僵尸主机、异常行为、漏洞攻击、命令与控制等。利用大数据分析技术,态势感…...
VM Virutal Box的Ubuntu虚拟机与windows宿主机之间设置共享文件夹(自动挂载,永久有效)
本文参考如下链接 How to access a shared folder in VirtualBox? - Ask Ubuntu (1)安装增强功能(Guest Additions) 首先,在网上下载VBoxGuestAdditions光盘映像文件 下载地址:Index of http://…...
【docker集群应用】Docker--harbor私有仓库部署与管理
文章目录 Harbor特性Harbor构成Harbor部署与管理Harbor 部署实例环境准备1. 部署 Docker-Compose 服务2. 部署 Harbor 服务(1) 下载并解压 Harbor 安装程序(2) 修改 Harbor 配置文件 3. 启动 Harbor4. 查看 Harbor 启动镜像5. 创建一个新项目6. 在其他客户端上传镜像 维护管理 …...
【优选算法】位运算
目录 常见位运算总结1、基础位运算2、给一个数n,确定它的二进制位的第x位上是0还是13、将一个数n的二进制位的第x位改成14、将一个数n的二进制位的第x位改成05、位图的思想6、提取一个数n的二进制位中最右侧的17、将一个数n的二进制位中最右侧的1变为08、位运算的优…...
2.mybatis整体配置
文章目录 mybatis-config.xml介绍SqlSessionFactoryBuilderXMLConfigBuilderpropertiessetting类型别名(typeAliases)扫描插件(plugins)解析objectFactory(对象工厂)解析objectWrapperFactory解析reflectorFactorysettingsElement()方法环境配置…...
js中判断数组和判断对象的方法
判断数组 Array.isArray() 方法 这是最推荐的方法,简单明了。它可以检测数组的情况,并且不会误报其他类型。 const arr [1, 2, 3]; console.log(Array.isArray(arr)); // trueconst notArray { key: value }; console.log(Array.isArray(notArray))…...
【godot】如何立刻(实时)进行碰撞检测?
因为最近在做帧同步方面的内容,所以发现了这个问题。 方案1:用Area2d进行碰撞检测,绑定body_entered信号。 缺陷: Area2d的碰撞检测只会每个物理迭代中只会执行一次,即在physics_process()结束后执行一次。 场景&a…...
讨论JAVA、JVM与Spring
Q1: 作为一个JAVA开发人员,对于jvm肯定不陌生,但很多人对它不陌生也仅止于概念上,而且对概念也是模糊不清的,但jvm实际是java程序运行在其中的实际存在的环境,对它的理解应该要是具象化的。 我们还是从一项技术产生的…...