之前的文章介绍了我最近开发的一款工具软件 移动工具箱,然而安装包放在华为应用市场上面,如果不安装华为应用市场就无法下载软件,无奈,只能自己从零搭建一个服务器来进行应用的宣传和下载。搭建一个服务器是很简单的,这里我们将服务器的要求提高一些,以对标 “生产” 的标准进行要求,要做的东西比较多,故作此文,加以记录。
首先说下环境,腾讯云,CentOS 7.5 64 位,服务器采用 Java 完成,具体来说就是 Springboot. 大致罗列下要做的事情:
- 介绍服务器远程连接方式
- 进行基础的服务器安全配置
- 禁止 root 用户直接登录服务器
- 关闭 22 登录端口
- 警惕空密码账户
- 设置密码过期时间
- 设置密码复杂度要求
- 禁止 ping 服务器
- 最重要的,防止 rm -rf
- 搭建生产服务器环境
- 安装 ftp 服务
- 连接 ftp 服务器
- 安装 JDK
- 搭建 Springboot 环境
- 发布应用
- 在服务器中启动 Springboot 程序
- 指定虚拟机启动参数
- 编写服务器启动脚本程序
- 配置域名
1、介绍服务器远程连接方式
对于腾讯云,一种连接方式是直接使用腾讯云提供的在线的 webshell 进行登录,这种登录方式提供的是 ssh 登录。假如我们进行 ftp 登录来上传文件的话比较不方便。腾讯云的 webshell 还是比较好用的,不过一般我们推荐使用 Xshell 进行 ssh 登录,使用 xftp 进行 ftp 登录。可以到我的公众号后台回复 【服务器连接软件】 获取我打包好的软件。
拿到一个新的服务器,我们要做的第一件事情就是到控制台里去重置密码。对于密码,为了系统安全起见,应该选择比较复杂的口令,例如最好使用 8 位长的口令,口令中包含有大写、小写字母和数字,不应该包含单词,应该与姓名、生日等不相同。
按照上面的介绍重置密码之后就可以进行登录了,这里使用 Xshell 进行登录,登录方式比较简单,此处略过。
2、进行基础的服务器安全配置
2.1 禁止 root 用户直接登录服务器
为啥要禁止 root 登录呢?首先,root 这个用户是众所周知的,使用 root 用户增加了被攻击的风险。其次,root 权限比较高,不论是服务器拥有者还是服务器的协同开发都不应该直接使用 root 操作服务器。使用 root 用户,一旦出现操作意外,就可能会给服务器带来致命的危害。
禁止 root 登录之前先添加一个新的管理员用户,
# Step 1: 创建新用户 admin
adduser the_xxx_admin
# Step 2: 修改用户密码,密码也应该满足上述要求哦
passwd the_xxx_admin
# Step 3: 赋予该用户 su 执行权限
gpasswd -a the_xxx_admin wheel
这里增加了一个名为 the_xxx_admin (用户名不要太大众化)的管理员用户,并将其用户组设置为 wheel. wheel 在 linux 中是一个特殊的用户组,这个组被设计用来解决 su 指令的授权问题。也就是只有在 wheel 组里面的成员才能使用 su 切换到 root 用户。如果一个用户不在 wheel 组里面,即使使用 su 指令并正确地输入了密码也无法切换到 root 用户。wheel 用户组不仅具有 su 指令的权限,也具有 sudo 的权限,可以通过浏览 /etc/sudoers
文件来了解。
增加了新的用户之后并赋予 sudo 权限之后,我们就可以禁止 root 用户登录了:
- 修改
/etc/ssh/sshd_config
文件将#PermitRootLogin yes
修改为PermitRootLogin no
; - 使用
service sshd restart
重启 ssh 服务并验证登录效果即可。
此处修改文件的时候可以使用 vim /etc/ssh/sshd_config
命令,然后输入 /PermitRootLogin
定位到 #PermitRootLogin yes
所在的一行,输入 a
进入编辑模式,修改完毕之后使用 :wq!
退出即可。
重启之后再使用 root 进行登录,立刻显示 “服务器拒绝 ssh 连接”,然后使用新增的用户进行登录即可。
2.2 关闭 22 登录端口
主要是因为 22 端口登录已经是众所周知的了,如果我们使用其它端口实现 22 端口的功能可以减少被攻击的风险。修改登录端口需要修改 /etc/ssh/sshd_config
文件。在该文件中,我们先新增一个端口,推荐使用 10000 号以上的端口。注意这里应该先保留 22 端口,设置完毕并验证新的端口可以登录之后再删除 22 端口。还有需要注意的地方,验证新的接口是否可以登录之前一定要先打开防火墙,防火墙关闭的时候端口可以直接使用,而一旦防火墙打开,而你又没有使用防火墙打开该端口,那么防火墙可能会直接屏蔽该端口,导致你无法登录自己的服务器。
这里直接使用 vim 编辑 /etc/ssh/sshd_config
文件的时候应该会出现 Permission Denied
。此时,可以通过 sudo 命令来完成,
sudo vim /etc/ssh/sshd_config
与 sudo 类似的还有 su 命令。sudo
和 su
功能类似,区别在于 sudo
命令需要输入当前用户的密码,su
命令需要输入要切换到的用户的密码。 sudo
比 su
更合理一些,因为,比如如果希望某个用户切换到 root 用户,使用 su
的方式要求执行者必须知道 root 账户的密码,密码被很多人知道显然不安全。而 sudo
只要求确认当前执行者的身份,如果当前执行的用户在 sudoers
中被授予过访问 root 的权限,则它可以切换到 root 用户,这样我们既赋予了该用户切换到 root 的权限,又无需告知该他 root 账户的密码。此外,我们还可以通过在 sudoers
文件中进行配置来限制用户的权限,记录更多的用户日志等。
进入编辑模式之后找到 Port 22
并在下面新增一行 Port 10022
:
Port 22
Port 10022
然后,我们需要按照上述管理端口的逻辑开放 10022 端口。然后,重启 ssh 服务:
systemctl restart sshd # 或者 service sshd restart
如果验证登录成功,再将上面的 Port 22
注释掉,重启 ssd 服务然后再使用 22 端口登录,验证是否已经禁止。
此时,我再使用 22 端口进行登录,提示 Connection failed
,表明禁止 22 端口登录成功。
2.3 警惕空密码账户
空密码账户会增加系统的安全风险。使用如下指令查询:
cat /etc/shadow | awk -F: '($2==""){print $1}'
另外,可以通过修改 ssh 配置文件 /etc/ssh/sshd_config
来禁止空密码账户进行登录:
PermitEmptyPasswords no
2.4 设置密码过期时间
设置和查询密码有效期会用到指令 chage,该指令格式如下:
chage [参数] [数值]
常用参数:
- -m : 密码可更改的最小天数。为零时代表任何时候都可以更改密码。
- -M : 密码保持有效的最大天数。
- -W : 用户密码到期前,提前收到警告信息的天数。
- -E : 帐号到期的日期。过了这天,此帐号将不可用。
- -d : 上一次更改的日期。
- -I : 停滞时期。如果一个密码已过期这些天,那么此帐号将不可用。
- -l : 例出当前的设置。由非特权用户来确定他们的密码或帐号何时过期。
一般的使用示例如下。
首先查询用户密码的有效期:
chage -l admin
显示信息如下:
Last password change : Apr 07, 2020
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
我们可以使用 chage 指令来修改密码的过期时间,比如使用如下指令将密码的最大有效期设置为 99 天:
chage -M 99 admin
2.5 设置密码复杂度要求
有两种方式来设置密码复杂度。
一种方式是修改 /etc/login.defs
文件,这里面几个比较重要的选项。可以通过修改选项的值来设置对密码对要求:
PASS_MAX_DAYS 90 #密码最长过期天数
PASS_MIN_DAYS 80 #密码最小过期天数
PASS_MIN_LEN 10 #密码最小长度
PASS_WARN_AGE 7 #密码过期警告天数
另外一个方法是,修改 /etc/pam.d/system-auth
文件。编辑该文件,在下面这行进行配置即可:
password required pam_pwquality.so dcredit=-1 ucredit=-1 ocredit=-1 lcredit=0
配置的可选参数可以参考 /etc/security/pwquality.conf
文件。常用的参数如下:
- retry=N:定义登录/修改密码失败时,可以重试的次数;
- Difok=N:定义新密码中必须有几个字符要与旧密码不同。但是如果新密码中有1/2以上的字符与旧密码不同时,该新密码将被接受;
- minlen=N:定义用户密码的最小长度;
- dcredit=N:定义用户密码中必须包含多少个数字;
- ucredit=N:定义用户密码中必须包含多少个大写字母;
- lcredit=N:定义用户密码中必须包含多少个小写字母;
- ocredit=N:定义用户密码中必须包含多少个特殊字符(除数字、字母之外);
2.6 禁止 ping 服务器
禁止 ping 后,不让别人通过域名 ping 到你的 ip. 禁用后,你在 ping 自己的域名会给你返回服务商的 IP 并提示超时,这样你就可以减少 IP 暴露,增加一点安全。
实现的方式是:编辑 /etc/sysctl.conf
里面配置,如果没有添加上下面一行配置:
net.ipv4.icmp_echo_ignore_all=1
然后使用如下命令使配置生效:
sysctl -p
这样就禁止了对服务器的 ping 操作。如果要解除,只需要将上面的 1 换成 0 即可。
配置完毕之后在本地的命令行里输入 ping 你的ip
地址,如果显示请求超时,则说明配置成功。
2.7 最重要的,防止 rm -rf
rm -rf
这个梗想必大家都了解,这节我们不是要教你如何在服务器上面执行该操作,来观察它带来的喜剧效果,而是如何避免该操作带来的负面影响。需要注意的地方:下面的操作会使用 source 命令,这个指令也是万分危险的指令,必须慎重! 这个指令用来修改类似于 windows 中的环境变量,假如 source 出现问题,可能会导致几乎所有的命令都无法使用,非常危险。
实现的原理是对 rm
命令进行改写,将其关联到一个自定义脚本。首先,我们在 ~
目录下面一个隐藏的 .trash
文件和 .tools
文件夹,
# 创建 .trash 文件夹
mkdir .trash
# 创建 .tools 文件夹
mkdir .tools
# 检查创建结果
ls -al
然后,在 .tools
文件夹中创建一个名称为 remove.sh
的脚本,编辑其内容如下:
#!/bin/sh
trash_dir=~/.trash/`date +%Y%m%d`
if [ ! -d ${trash_dir} ] ;then
mkdir -p ${trash_dir}
fi
for i in $*
do
suffix=`date "+%H%M%S"`
if [ ! -d "${i}" ]&&[ ! -f "${i}" ];then # 首先判断是否是合法的文件或者文件夹
if [[ "${i}" != "-rf" && "${i}" != "-f" ]];then # 这里对-rf进行处理,因为mv指令后面没有-rf,-f参数
echo "[${i}] do not exist"
fi
else
file_name=`basename $i` # 取得文件名称
mv ${i} ${trash_dir}/${file_name}_${suffix}_${RANDOM}
echo "[${i}] delete completed"
fi
done
这里简单解释下这个脚本文件的内容吧。这个脚本文件按照文件名拼接的规则,在文件名中增加了日期信息(用来对同名文件进行区别),然后使用 mv 命令将指定对文件夹移动到 ~/.trash
目录下面。应该注意这里对 -rf
参数的处理。之前也看过一些博客的脚本,没有对这两个参数做处理,导致 mv
命令无法执行。
然后,我们修改 ~/.bashrc
文件,在末尾追加下面一行代码。将 rm 命令关联到指定的 Shell 文件:
alias rm='sh ~/.tools/remove.sh'
然后,使用如下命令来使我们对修改生效,
source ~/.bashrc
最后,在用户根目录下面创建文件夹,并使用 rm -rf 文件夹
指令测试效果。
这里本质上是把要删除的目录移动到了 .trash
目录下面。然后根据操作的日期对移除对文件夹进行管理。这无疑地会导致我们的文件夹越来越大,所以,我们要定期对该文件夹进行删除。这里,我们使用脚本来实现这个目标。
这里我们创建一个定时任务来执行删除操作。在 .tools
文件夹下面添加一个脚本文件 clean.sh
,编辑内容如下。其作用是找到回收站中修改日期大于 3 天的文件,执行真正的删除操作:
#!/bin/sh
trashdir=~/.trash
find ${trashdir} -mtime +3 -exec 'rm' -rf {} \;
然后,我们将该任务添加到 crontab 任务中。
使用 crontab -e
命令进入定时任务编辑界面,在最后面加入
0 3 * * * sh ~/.tools/clean.sh #每天 3:00 执行清理回收站的脚本
使用 service crond restart
重启 crontab 服务,使用 crontab -l
命令如果可以看到刚才添加的那段话,则证明添加成功。这里使用了一段 cron 表达式,Linux 的 cron 表达式和 Springboot 中的表达式起始单位有些不同,需要注意下。
另外,注意到上文中需要使用 source ~/.bashrc
才能使配置的 bash 文件生效。当用户重新登录的时候也必须这么做才能使我们的配置再次生效。作为程序员,这当然是无法容忍的。于是,我们可以用下面的方法来解决这个问题,来让每次登录服务器之后我们的配置自动生效,
# 编辑 .profile 文件
vim .profile
# 在文件中增加如下的配置
if [ -s ~/.bashrc ]; then
source ~/.bashrc;
fi
# 或者直接增加下面的代码也行,不过简单粗暴了点
source ~/.bashrc
这样配置之后,每次启动重新登录的时候我们的配置就可以自动生效了。
最后的一个问题,如果用户目录下面不存在 .bashrc
或者 .profile
文件,那么可以从 /etc/skel
文件下面将其拷贝到用户目录下面,然后再做上面的配置即可。
3、搭建生产服务器环境
上面的配置已经做到了安全性的基本要求。下面着手搭建服务器生产环境。既然是基于 Java 的生产环境,那么要求安装的东西不多,一个必备的 ftp 服务,一个 JDK 环境即可。当然,正式的话还有数据库 MySQL, Redis,以及常用的中间件 MQ、ES 等。这里我们先搭建一个基础的 Java 环境,能运行起 Springboot 即可,所以 JDK 就够了。
3.1 安装 ftp 服务
Ftp 还是比较重要的,我一般使用 ftp 上传要发布的 jar 包。另外,个别软件的安装包比较大,而且存在网络连接问题,导致下载速率比较低,因此,有时候会选择本地下载完成安装包之后通过 ftp 上传到服务器再进行安装。所以,ftp 是非常重要的一个环节。
先安装 vsftpd,
yum install -y vsftpd
安装之后会生成 /etc/vsftpd/
和 /var/ftp/
,其中
-
/etc/vsftpd/
目录下面包含四个文件:-
ftpusers
指定了哪些用户不能访问 ftp 服务 -
user_list
当 vsftpd 里userlist_deny=NO
时,只允许这里的用户访问 ftp 服务;当 vsftpd 里userlist_deny=YES
(默认) 时,不允许这里的用户 访问 ftp 服务 -
vsftpd.conf
是 vsftpd 的核心配置文件 -
vsftpd_conf_migrate.sh
是 vsftpd 操作的一些变量和设置脚本
-
/var/ftp/
是匿名访问 ftp 服务器的时候能够访问的目录
使用 vim vsftpd.conf
编辑配置文件,比较重要的配置项说明:
# 是否允许匿名登录,默认 YES,为了安全起见,我们应该将其关闭
anonymous_enable=NO
# 是否允许本地账号(系统账号)登录
local_enable=YES
# 是否运行上传操作,如果要运行上传那么就要开启这个配置
write_enable=YES
# 是否以独立运行的方式监听服务,ftp 服务的运行模式,NO 时表示 xinetd 模式;YES 时表示 standlone 模式
listen=NO
# 控制 user_list 的功能,允许 user_list 列表用户登录ftp
userlist_enable=YES
# 控制 user_list 的功能,不允许 user_list 列表用户登录ftp
userlist_deny=YES
# 这个指令应该谨慎!!因为当其设置为 YES 的时候,虽然可以登录服务器,但是登录的 ftp 用户可以访问上级目录
chroot_local_user=NO
# 不受限制的用户列表,在 vsftpd 目录下面建立 chroot_list 文件,写入指定的用户名即可
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list
allow_writeable_chroot=YES # 这句必须有
其他配置还可以选择:
# 地址:设置监听f t p服务的ip地址,默认监听所有IP地址
listen_address=IP
# 设置监听ftp服务的端口号
listen_port=21
# 允许下载权限
download_enable=YES
# 用户切换进入目录时显示 “.message”文件(如果已存在)的内容
dirmessage_enable=YES
# 启用xferlog日志,默认记录到 /var/log/xferlog
xferlog_enable=YES
# ftp日志格式
xferlog_std_format=YES
# 数据连接端口号默认20
connect_from_port_20=YES
# 禁止被动模式连接;默认允许被动模式连接
pasv_enable=NO
# 起始端口号
pasv_max_port=21600
# 结束端口号
pasv_min_port=21700
# 开启PAM验证
pam_service_name=vsftpd
# 限制多个客户端同时连接(0为无限制)
max_clients=0
# 允许相同IP地址访问ftp连接次数(0为无限制)
max_per_ip=0
# ftp的访问控制列表提升安全性使用
tcp_wrappers=YES
配置完成之后就可以使用以下命令开启服务:
service vsftpd start
另外还需要配置 系统的安全模块 SELinux:
# Step 1: 打开 SELinux 文件进行编辑:
vim /etc/sysconfig/selinux
# Step 2: 将 SELINUX=1 修改为 disabled
然后,我们需要添加一个独立的用户来进行 ftp 访问,并且限制 ftp 用户只能进行 ftp 连接,不能进行服务器登录,不应该将 ftp 用户和登录用户混为一谈,以此来进一步保障服务器的安全性:
# Step 1: 添加用户,语法是 useradd [-mMnr][-c <备注>][-d <登入目录>][-e <有效期限>][-f <缓冲天数>][-g <群组>][-G <群组>][-s <shell>][-u <uid>][用户帐号]
# 用户登录终端设为 /sbin/nologin,即使之不能登录系统,只能访问 ftp
useradd ftpuser -d /home/ftpuser -s /sbin/nologin
# Step 2: 修改用户密码
passwd ftpuser
# Step 3: 设置用户权限,/path/you/set 为刚刚设定的该用户 ftp 的根目录
chown -R ftpuser /home/ftpuser
# Step 4: 再到 /etc/vsftpd 目录下新建(或者修改) chroot_list 文件 并添加允许访问的用户
# Step 5: 重启 ftp 服务
service vsftpd restart
# Step 6: 若出现无法上传或者读取目录情况,设置之前指定的目录的读写权限
chmod 777 /home/ftpuser
3.2 连接 ftp 服务器
1. 远程连接 ftp
在 Mac 上面,可以使用 finder 连接 ftp 服务器,缺点是只能下载不能上传。参考文章 《Mac自带FTP工具用法》 进行连接即可,另外还可以使用 iterm2 连接。iterm2 是 Mac 上的终端神奇。其安装和配置可以参考 《MAC终端神器iterm2——告别黑白》,然后需要在 Mac 上面安装 ftp,参考 《Mac ftp 命令安装即使用》。至于 Windows 上面,直接使用 Xftp 即可。可以到我的公众号后台回复 【服务器连接软件】 获取我打包好的软件。
2. 连接 ftp 服务器的问题
用 xftp 连接提示无法打开,无法显示远程文件夹:选择 “属性->选项->将使用被动模式” 选项去掉即可。
3.3 安装 JDK
需要注意:Java SDK 和 ElasticSearch 等其他的中间件的版本对应关系,一般来说 JDK 8+ 可以满足大部分需求。
到官方网站 JDK 官方下载地址 下载 JDK 即可。在官网下载之前需要先进行用户登录,获取到下载链接之后使用 wget 命令进行下载即可:
wget http://download.oracle.com/otn-pub/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/jdk-8u171-linux-x64.tar.gz?AuthParam=1531155951_4e06a4d17c6c1dbfb8440352e19dd2ae
注意下载后缀中包含 AuthParam
参数,如果链接不包含这个参数,下载之后可能无法使用。
如果从官网下载速度比较慢,可以尝试从华为镜像下载:华为 JDK 镜像。
进行安装:
# Step 1: 创建安装目录
mkdir /usr/local/java/
# Step 2: 解压至安装目录
tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/local/java/
设置环境变量:
# Step 1:打开 profile 编辑模式
vim /etc/profile
# Step 2:在 profile 文件末尾追加环境变量
export JAVA_HOME=/usr/local/java/jdk1.8.0_171
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
# Step 3:使 profile 生效
source /etc/profile
# Step 4:添加软链接
ln -s /usr/local/java/jdk1.8.0_171/bin/java /usr/bin/java
# Step 5: 检测是否安装成功
java -version
3.4 搭建 Springboot 环境
如果仅仅是提供一个下载服务的话,还是比较简单的,直接使用 Springboot 的 web 和模板引擎构建一个 html 页面,apk 放到 static 目录下即可。也有问题需要注意下,即如果这样简简单单地搭建的一个服务是不安全的,因为没有做限流处理。而一般我会使用 Redis 做限流,但是这样就要介绍如何安装 Redis 以及 Redis 的各种安全配置等……所以,目前先不做,当前能够展示应用详情,并且能够给用户提供下载渠道即可。
4、发布应用
4.1 在服务器中启动 Springboot 程序
Springboot 应用开发完毕,直接在项目根目录执行 mvn install
编译打包即可。打出来的包,通过 ftp 上传到服务器。
对于 jar 包,如果想要在后台启动,可以使用如下指令,
nohup java -jar target/包名.jar --spring.profiles.active=lt &
也就是使用 nohup
并且末尾追加了一个 &
。如果不使用 nohup
只追加一个 &
,也可以后台启动,但是这种方式在 ssh 会话结束之后程序就会停止。
按照上面 nohup
的启动方式,会在当前目录下面生成一个名为 nohup.out
的文件,终端的内容会被写入到这个文件当中。使用这种启动方式的时候终端不会显示启动过程,所以我们只能通过获取 nohup.out
的内容来判断程序是否启动成功。动态获取文件的内容可以使用指令 tail -f nohup.out
来获取。当然,如果希望将输出人日志重定向到某个具体的文件或者不输出日志(重定向到 /dev/null
)也是可以的。比如下面的命令用来将日志重定向到 catalina.out 文件:
nohup java -jar xxx.jar > catalina.out 2>&1 &
查看 Springboot 工程的进程使用如下命令,
ps aux | grep "java -jar" | grep -v "grep"
上述显示的内容中包含了进程的 pid,如果要杀掉某个进程,直接输入下面的命令即可:
kill -9 pid
4.2 指定虚拟机启动参数
1. 远程连接虚拟机
首先,我们需要远程连接上我们的应用来观察虚拟机的状况。不论是排查线上问题还是项目启动之前虚拟机参数调整,这个都比较重要。常用的连接工具有 jconsole 和 jvisualvm 两个。让我们的虚拟机可以被远程监控,需要我们做小小的配置。
首先,我们需要修改虚拟机远程连接的密码。进入 jre 安装目录下面的 management 目录中,比如我的 jdk1.8.0_181/jre/lib/management
。然后,复制 jmxremote.password.template
并将其重命名为 jmxremote.password
,然后注释掉最后两行的注释,这里的 monitorRole 就是默认的远程连接的登录账号,紧随其后的就是登录密码。需要把默认的密码修改掉,增加服务器的安全性。
然后,我们需要在项目的启动参数中增加几个参数来配置并启用远程连接,比如我的设置了之后的参数如下:
nohup java -jar -Djava.rmi.server.hostname=23.123.122.31 -Dcom.sun.management.jmxremote.port=11162 -Dcom.sun.management.jmxremote.rmi.port=11163 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true $portal_app_jar > portal.out 2>&1 &
这里我们的参数配置及其含义如下:
-
java.rmi.server.hostname
:远程连接的时候的 ip,就是你的服务器的真实 ip 地址; -
com.sun.management.jmxremote.port
:远程连接的时候的端口,不能和应用的端口相同; -
com.sun.management.jmxremote.rmi.port
:远程 rmi 连接的时候的端口,不能和应用的端口相同; -
com.sun.management.jmxremote.ssl
:是否使用 ssl 连接方式; -
com.sun.management.jmxremote.authenticate
:是否启用身份认证功能,这个应该启用,否则就别人不需要输入密码就可以直接连接并查看你的虚拟机了。
这样配置完成之后开发上面填写的两个端口,然后重新启动应用。
本地远程连接虚拟机的时候使用 jconsole 和 jvisualvm 皆可。这两个可执行文件放在 jdk 的 bin 目录下面。双击打开之后直接连接即可。
2. 应用启动参数配置
首先是一些官方的参考资料
- Springboot 核心配置参数的官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#core-properties
- Oracle 上面的虚拟机参数调优文章,包括虚拟机版本、垃圾收集器选择、设置堆大小等方面的调优提示:https://docs.oracle.com/middleware/11119/wls/PERFM/jvm_tuning.htm#i1146060
常用的参数:
-XX:MetaspaceSize=128m (元空间默认大小)
-XX:MaxMetaspaceSize=128m (元空间最大大小)
-Xms1024m (堆默认大小也是最小的大小)
-Xmx1024m (堆最大大小)
-Xmn256m (新生代大小)
-Xss256k (棧最大深度大小)
-XX:SurvivorRatio=8 (新生代分区比例 8:2)
-XX:+UseConcMarkSweepGC (指定使用的垃圾收集器,这里使用CMS收集器)
-XX:+PrintGCDetails (打印详细的GC日志)
具体取值多少要根据自己的应用的类型、并发量和服务器环境综合分析,可以结合上面的一些文档为自己的程序指定参数。
4.3 编写服务器启动脚本程序
当然了,指定服务器启动参数还是比较繁琐的,所以,通常我们会编写启动脚本,然后通过执行脚本来启动和终止程序。下面是一段参考代码,
#!/bin/bash
# 程序运行脚本程序
# 作者:王守恒
# 定义要启动的程序的 Jar 文件,不指定 Jar 文件的版本
app_jar=box.jar
# 脚本文件使用说明
usage() {
echo "|====================================================================="
echo "| 脚本文件用法说明 |"
echo "|====================================================================="
echo "| sh 脚本名称.sh [start|stop|restart|status] [prev] |"
echo "| |"
echo "| 参数说明 |"
echo "| |"
echo "| start: 启动程序 |"
echo "| stop: 停止程序 |"
echo "| restart: 重新启动程序 |"
echo "| status: 程序状态 |"
echo "| |"
echo "| prev: 可选参数,如果指定该参数,则会将程序的运行日志输出到指定 |"
echo "| 的文件中,否则不输出,建议项目正式发布的时候不启用该选项 |"
echo "|====================================================================="
}
# 程序启动函数
# 函数体内使用 $ 获取的参数是函数调用的时候传入的参数,
# 而不是整个脚本被调用的时候传入的参数
start() {
# 运行portal程序
vm_opt='-XX:NewSize=216m -XX:MaxNewSize=216m -XX:SurvivorRatio=8 -Xms1024m -Xmx2048m -XX:+PrintGCDetails -Djava.rmi.server.hostname=你的ip -Dcom.sun.management.jmxremote.port=你的端口 -Dcom.sun.management.jmxremote.rmi.port=你的端口 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true'
if [[ $1 == "prev" ]]; then
# 预览
nohup java -jar $vm_opt $app_jar > box.out 2>&1 &
echo "box[prev] start succeed"
else
nohup java -jar $vm_opt $app_jar > /dev/null &
echo "box app start succeed"
fi
}
# 程序停止函数
stop() {
# 获取程序的pid并kill之
is_exist $app_jar
if [ $? -eq "0" ]; then
kill -9 $pid
echo "Box was killed with pid ${pid}"
else
echo "Box is NOT running"
fi
}
# 程序状态函数
status() {
is_exist $app_jar
if [ $? -eq "0" ]; then
echo "Box is running with pid ${pid}"
else
echo "Box is NOT running"
fi
}
# 程序重新启动函数
restart() {
stop $app_jar
start $app_jar
}
# 判断指定的进程存不存在
is_exist() {
pid=`ps -ef | grep $1|grep -v grep | awk '{print $2}'`
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
# 根据用户输入参数选择执行的函数
case "$1" in
"start")
start $2
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac
# End
# =========================================================================
这里我区分了预览和正式环境,因为有时候应用启动之前就因为某些配置错误无法启动,此时如果使用正式环境的话,日志会按照我们上述的配置被丢掉,从而无法配查问题。可以通过启动的时候指定一个 prev 参数将启动过程中的日志重定向到当前的目录下的指定文件中。这里主要有几个功能吧:启动、重启、判断是否启动以及指令说明。
4.4 配置域名
按照上面的配置我们已经可以可以使用 ip 地址进行访问了,但是我们还是要配置一下域名。这里我使用的是之前的一个子域名。当然,除了配置域名之外还要配置一下 CDN,配置了 CDN 之后的访问逻辑如下:
box.meiyan.tech -> CDN 域名 -> CDN 域名指定的 ip 地址或者 ip 地址加端口号
配置 CDN 比直接使用域名映射到 ip 地址的方式还有一个好处,就是在 ping 指定的域名的时候不会直接暴露 ip 地址,这样可以阻挡一步分流量攻击。
总结
这里介绍了搭建服务器和服务器安全配置相关的知识,也涉及到了一些 linux 指令,因篇幅的原因,上面仅仅介绍了一部分,更无法详细进行介绍。此外,我写了完整的十几篇文章,从基础的 linux 指令到各种常用的中间件安全配置等详细的知识,感兴趣的话关注下吧。这里提到的 移动工具箱 是我最近开发的一款 Android 工具软件,非常实用,其中包含了很多对开发者非常实用的功能,感兴趣可以下载尝试。