从零搭建基于 Java 的服务器生产环境

实战指南:从零搭建Java项目部署环境——Nginx与服务器配置详解 本文详细介绍了从零搭建Java项目部署环境的完整流程,包括服务器选择、Java环境配置、Nginx安装与高级配置技巧。通过实战案例演示了反向代理、HTTPS配置和负载均衡的实现,并提供了常见问题排查和性能调优建议,帮助开发者快速掌握Java项目部署的核心技能。 阅读详情

之前的文章介绍了我最近开发的一款工具软件 移动工具箱,然而安装包放在华为应用市场上面,如果不安装华为应用市场就无法下载软件,无奈,只能自己从零搭建一个服务器来进行应用的宣传和下载。搭建一个服务器是很简单的,这里我们将服务器的要求提高一些,以对标 “生产” 的标准进行要求,要做的东西比较多,故作此文,加以记录。

首先说下环境,腾讯云,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 用户登录了:

  1. 修改 /etc/ssh/sshd_config 文件将 #PermitRootLogin yes 修改为 PermitRootLogin no;
  2. 使用 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 [参数] [数值]

常用参数:

  1. -m : 密码可更改的最小天数。为零时代表任何时候都可以更改密码。
  2. -M : 密码保持有效的最大天数。
  3. -W : 用户密码到期前,提前收到警告信息的天数。
  4. -E : 帐号到期的日期。过了这天,此帐号将不可用。
  5. -d : 上一次更改的日期。
  6. -I : 停滞时期。如果一个密码已过期这些天,那么此帐号将不可用。
  7. -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 文件。常用的参数如下:

  1. retry=N:定义登录/修改密码失败时,可以重试的次数;
  2. Difok=N:定义新密码中必须有几个字符要与旧密码不同。但是如果新密码中有1/2以上的字符与旧密码不同时,该新密码将被接受;
  3. minlen=N:定义用户密码的最小长度;
  4. dcredit=N:定义用户密码中必须包含多少个数字;
  5. ucredit=N:定义用户密码中必须包含多少个大写字母;
  6. lcredit=N:定义用户密码中必须包含多少个小写字母;
  7. 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/,其中

  1. /etc/vsftpd/ 目录下面包含四个文件:

    1. ftpusers 指定了哪些用户不能访问 ftp 服务
    2. user_list 当 vsftpd 里 userlist_deny=NO 时,只允许这里的用户访问 ftp 服务;当 vsftpd 里 userlist_deny=YES(默认) 时,不允许这里的用户 访问 ftp 服务
    3. vsftpd.conf 是 vsftpd 的核心配置文件
    4. vsftpd_conf_migrate.sh 是 vsftpd 操作的一些变量和设置脚本
  2. /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 &

这里我们的参数配置及其含义如下:

  1. java.rmi.server.hostname:远程连接的时候的 ip,就是你的服务器的真实 ip 地址;
  2. com.sun.management.jmxremote.port:远程连接的时候的端口,不能和应用的端口相同;
  3. com.sun.management.jmxremote.rmi.port:远程 rmi 连接的时候的端口,不能和应用的端口相同;
  4. com.sun.management.jmxremote.ssl:是否使用 ssl 连接方式;
  5. 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 工具软件,非常实用,其中包含了很多对开发者非常实用的功能,感兴趣可以下载尝试。

CentOS服务器从零搭建自动化测试环境:Python、Docker与Jenkins实战 在软件开发和运维领域,自动化测试是保障代码质量、提升部署效率的核心实践。其原理是通过预设脚本模拟用户操作或接口调用,自动执行测试用例并验证结果,从而替代繁琐的手动测试。这项技术的价值在于能够实现快速反馈、持续集成,并确保软件在迭代过程中的稳定性。典型的应用场景包括Web应用的后端接口测试、移动端App的UI自动化以及每日构建验证等。本文聚焦于在无图形界面的CentOS服务器上,系统化部署包含Python3、Java、Node.js、Docker及Jenkins的完整工具链,解决依赖管理、容器化部署和持续集成 阅读详情

相关推荐

我的世界Bukkit服务器插件开发教程(零)环境搭建

文章目录前言准备导入外库 前言 开发一款插件是比较简单的,当你有不会的时候可以去参考api 准备 编程软件IDEA jdk8 一台云服务器 核心文件(spigot-1.17.jar) 导入外库 打开你的idea,创建一个项目、包包 之后右键项目,选择打开模块设置 选择库,点击右上的+,选择Java 选择核心文件,点击确定 点击应用就可以了 之后就可以编写插件了 上一篇:我的世界Bukkit服务器插件开发(负一) 下一篇:我的世界Bukkit服务器插件开发(一) ......

一个无聊的程序猿 8961

云服务器springboot jar项目开启jmx remote监控-解决无法连接的问题

前言 服务器上跑了一个springboot项目,尝试开启jmx远程监控,观察下jvm的情况。按照网上的一些文章去添加了参数,发现无法连接远程jmx,如下所示 经过一番排查,终于解决问题。 服务器端jar包启动命令示例 java \ -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.local.only=false \ -Dcom.sun.management.jmxremote.authenticate=false

weixin_43118901的博客 4326

windows 环境下搭建MQTT服务器(详细)

一、序言 二、参考链接 三、工具下载 四、安装及环境配置 五、注意事项 一、序言 参考了网上的文档,发现好多写的不够详细,那就自己记录一下吧,为后来人提供方便,也省得自己以后如果再用还要再去翻,并且记录下自己遇到的一些坑。 二、参考链接 https://blog.youkuaiyun.com/yannanxiu/article/details/52703946 //参考了这个MQTT服务器搭建流程发现需要JDK环境,于是又去搜了下面这个讲JDK的链接 https://www.cnblogs.com/zhangzhixi

weixin_42560250的博客 7931

15分钟从零开始搭建支持10w+用户的生产环境(一)

前言 这是一个基于中小型企业或团队的架构设计。 不考虑大厂。有充分的理由相信,大厂有绝对的实力来搭建一个相当复杂的环境。 中小型企业或团队是个什么样子? 开发团队人员配置不全,部分人员身兼开发过程上下游的数个职责; 没有专职的维护人员,或者维护人员实力不足以完全掌控生产和开发环境。 这种情况下,过于复杂的生产环境设计,规划、安装、调试、修改会牵扯太多的精力。一旦使用过程中出现问题,涉及的技术复杂性会带来不可预估的灾难。 同时,中小型团队的系统,也有其特殊要求,主要表现在: 生产环境的搭建要简单。这个主

老王Plus 339

基于wxWidgets框架,使用DialogBlocks建立OpenGL界面

前言 之前公司要求使用wxWidgets做GUI,基于OpenGL图形内核,开发三维可视化工具。目前初步开发工作基本已经完成,剩下都是完善了。这里记录一下最开始的框架搭建过程(当然是简化版啦)。wxWidgets结合OpenGL开发可以实现跨平台应用,再结合CMake和VS Code,整体开发工具用习惯了会感觉非常顺手。 界面编辑 首先,使用DialogBlocks新建一个工程,这里工程目录...

cyberobot的博客 2748

【第4章 光模块实测方法总结(环境搭建、眼图测试、接收测试、注意事项)】

本文系统介绍了光模块测试的完整流程与关键要点,涵盖低速模块到3.2T PAM4超高速模块的测试方法。内容包括:1)测试环境搭建(光路/电路要求);2)核心测试项目(眼图分析、接收灵敏度/饱和测试、误码压力测试);3)PAM4专项测试(TDECQ、RLM线性度等);4)可靠性测试(温循、电压、老化);5)八大注意事项(如禁止脏端面测试、长短距混插等)。特别强调高速模块对测试环境的高敏感性,需重点关注波形质量而非单纯光功率,并需进行严格压力测试才能暴露潜在问题。

学无止境 432

生产环境--系统搭建--基础环境搭建

环境要求 安装方式选择最小安装;要求/(根)、/home及/var分区空间均在40g以上(项目正式系统可根据实际情况往上调整) 交换分区及内存应在8g以上(项目正式系统可根据实际情况往上调整) 一、创建用户 1.1、建立具有administrator权限的新用户,并且以该用户登录 1.1.1、增加hd用户 [root@localhost home]# sudo adduser hd [root@localhost home]# sudo passwd hd 更改用户 hd 的密码 。 新的

zhou920786312的博客 1580

验证(uvm常见问题)--子类和父类的句柄和对象问题

sv中的子类和父类 在sv中,有如下两个类,child继承于parent。然后在test module中,正确转换的方法如下面所示。其中c1,c2,p1 都指向了同一个子类的对象c1。总结如下: 一个子类的对象是包括子类的成员变量,方法和父类的成员变量,方法。 子类的句柄c1可以直接赋值给父类的句柄p1,此时p1只可以访问父类的成员变量和方法,或者子类的虚方法,比如下面调用p1.display是...

q876507447的博客 7629

生产环境搭建和部署

在apollo目录下新建apollo-configservice目录,从课件中拷贝相关文件进来(jar+zip+Dockerfile)在apollo目录下新建apollo-adminservice目录,从课件中拷贝相关文件进来(jar+zip+Dockerfile)在apollo目录下新建apollo-portal目录,从课件中拷贝相关文件进来(jar+zip+Dockerfile)自己编写或从课件中找到Dockerfile文件并像上图一样复制到对应目录中。

lastingboy的博客 1512

高级技能-高可用和容灾-两地三中心、异地多活架构

两地三中心和异地多活是当前主流的跨地域高可用架构方案。两地三中心通过生产中心、同城灾备和异地灾备的组合,提供多级容灾能力,适合对数据安全要求高的行业。异地多活则采用单元化设计,多个站点同时服务,提升资源利用率,但需解决网络延迟、数据冲突等挑战。两种架构在RTO/RPO、一致性、改造成本等方面各具特点,企业应根据业务规模、一致性要求和预算进行选择,可考虑从同城双活起步,逐步向异地多活演进。混合架构可能是平衡容灾与多活的务实方案。

zhongjianfeng100的博客 168

PHP实现获取本机ip及mac地址​(附完整源码)

PHP实现获取本机ip及mac地址​(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 351

生产环境服务器环境搭建+ 项目发布

生产环境服务器环境搭建 安装jdk 安装 openjdk-8-jdk 在 ubuntu-16.04 系统中通过以下命令: 1.sudo add-apt-repository ppa:jonathonf/openjdk 2.sudo apt-get update 3.sudo apt-get install openjdk-8-jdk 输入 java -version 查看是否安装正确,输出如下...

weixin_30716725的博客 540

如何使用 Python 爬虫爬取滴滴打车信息:获取司机和乘客数据

滴滴打车作为中国最大的打车平台之一,提供了丰富的司机和乘客数据,包括司机的车辆信息、乘客的评价、行程数据等。公开的司机和车辆信息(如司机的名字、车辆类型、评价等)可以通过网页直接获取,而乘客的个人信息和具体行程数据通常会受到隐私保护。在滴滴打车的网页中,司机的信息可能以特定的 HTML 标签存在,例如包含司机名称、车辆类型、车辆等级等信息。我们需要分析网页的 HTML 结构,找到这些数据所在的标签。同时,对于涉及到隐私的用户数据(如乘客的行程信息、用户评价等),我们必须特别谨慎,避免侵犯他人的隐私。

2201_76125261的博客 1916

Tomcat安装配置全攻略:从零搭建Java Web服务器到生产环境部署

Servlet容器是Java Web应用运行的核心环境,它负责处理HTTP请求、管理Servlet生命周期并提供JSP支持。其工作原理是通过实现Java EE(现Jakarta EE)规范,将Web应用部署在容器内执行。这项技术的价值在于为Java Web开发提供了标准化、可移植的运行平台,极大简化了Web服务器的搭建与管理。在实际应用中,无论是传统企业级系统还是现代微服务架构,Servlet容器都扮演着关键角色。本文聚焦于业界广泛使用的Apache Tomcat,详细解析其版本选择策略、环境变量配置、性能

weixin_33883104的博客 235

【异常】Warp终端AI功能403封禁报错I‘m sorry, I couldn‘t complete that request.Request failed with error: ErrorSta

本文针对Warp终端出现的AI功能定向封禁报错,完整还原脱敏后的报错信息、深度解读报错本质,并提供分优先级的全流程可落地解决方案,可直接用于技术排查、内部知识库归档。

奶爸的编程之路,也就一周冷个三天 265

Arcgis中的模型构建器技术之按属性批量建库并对应输出

好久没更新了,之前我们已经介绍过四至点提取模型,前两天有同事问怎么样按属性批量建数据库并对应输出相关图斑。比如将一个县的永农数据按乡镇建立数据库并将对应乡镇的永农数据输出到相应的数据库里。今天就介绍一下相关的模型构建过程。

weixin_44671081的博客 516

从零搭建Nexus私有仓库:生产级部署完整指南,附8G内存配置与安全权限配置

本文详细介绍了在DigitalOcean云服务器上部署生产级Nexus私有仓库的完整流程。从选择8GB内存的服务器配置开始,到安装Java8、下载解压Nexus软件包,再到创建专用用户、配置权限和安全启动服务。重点强调了生产环境的关键注意事项:必须使用专用用户而非root运行服务、正确设置目录权限、开放8081端口防火墙等。通过这8个标准化步骤,读者可以快速搭建一个安全可靠的Nexus制品库,为后续CI/CD流程奠定基础。

医药/LIMS实验室IT · Office自动化 · .NET+Vue全栈 · 鸿蒙实战 · 欢迎技术交流 718

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

CentOS 9服务器从零部署到生产环境配置全指南

Linux服务器操作系统是企业IT基础设施的核心基石,其稳定性和安全性直接关系到业务连续性。CentOS作为企业级Linux发行版的代表,以其与RHEL的紧密兼容和长期支持而备受青睐。从系统架构原理来看,一个生产就绪的服务器不仅需要稳定的内核和软件包管理,更涉及网络配置、安全策略、服务管理和性能调优等多个技术层面。在工程实践中,通过合理的分区规划、最小化安装、防火墙配置和SSH安全加固,可以构建一个高效且安全的运行环境。无论是部署Python、Node.js、Java等开发栈,还是配置MySQL、Nginx

weixin_33391446的博客 372

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Linux服务器上Jenkins自动化部署实战:从零搭建到安全加固

持续集成与持续交付(CI/CD)是现代软件工程的核心实践,旨在通过自动化流程提升开发效率和代码质量。其核心原理在于将代码构建、测试、部署等环节串联为自动化流水线,减少人工干预,实现快速、可靠的软件交付。Jenkins作为一款开源的自动化服务器,凭借其强大的插件生态和灵活性,成为实现CI/CD流水线的关键技术工具,广泛应用于Web应用部署、容器化构建等场景。本文聚焦于在Linux环境下部署Jenkins,涵盖OpenJDK环境配置、服务安装、插件管理及Nginx反向代理配置等关键步骤,为构建企业级自动化部署平

weixin_30301449的博客 523

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

从零到一:用MCP Java SDK构建AI工具链的实战指南

本文详细介绍了如何使用MCP Java SDK从零开始构建AI工具链,包括基础环境搭建、服务器构建、高级功能开发及实战应用。通过MCP Java SDK,开发者可以轻松将AI能力集成到Java应用中,实现高效的工具链开发与集成。

1a2s3d4f5g的博客 772

快速搭建Java生产环境

快速搭建一个java的生产环境 (本文使用于有一定基础的编程人员,如果小白的话请仔细,一步一步按照本文来 也可配置成功,有问题可在下方评论) 1.JDK 看好自己电脑的版本 X32/X64,然后下载一个版本。并不是越新越好,一般都是1.5、1.7 官网 http://www.oracle.com/technetwork/java/index.html,官网有时候会卡 我在自己

幻凡ss 2965

关于服务器环境搭建

前言 在很多新项目中,都会用到环境搭建的情况,今天教大家如何在服务器中部署应用的环境搭建。 一、搭建环境是什么? 搭建环境是指建立运行程序文件的基础环境,比如服务运行需要装什么软件都需要哪些程序,服务器的部署就是搭建环境 整理了很久,刚开始搭建环境的时候连软件都不认识,也不知道这些服务有什么用,没办法只能一边做一边百度,辛苦了很久,下面给大家分享一下自己搭建环境的一些心得和步骤,谢谢大家 二、使用步骤 1.确定软件清单及版本 以下是我们今天要部署的软件...

weixin_51955218的博客 1万+

kafka生产环境集群搭建

三台服务器 准备工作 安装java环境 搭建zookeeper集群 搭建kafka集群 服务器配置 主机名 IP地址 硬件配置 kafka-1 192.168.1.162 24CPU、46G内存、600G存储 kafka-2 192.168.1.166 24CPU、64G内存、600G存储 kafka-3 192.168....

LMC技术人生专栏 1947

从零搭建Java环境

摘要:本文记录了Java开发环境的搭建流程,包括JDK安装与环境变量配置、IDEA安装与激活、MySQL数据库安装及Navicat可视化工具使用、MySQL与IDEA的连接配置、Tomcat服务器部署以及Maven项目构建工具的安装与本地仓库设置。重点解决了MySQL时区问题和Maven下载速度慢的常见问题,为开发者提供了完整的Java开发环境配置指南,适合换机或初次搭建环境时参考。(149字)

qq_46508774的博客 714

超详细的Java Web环境的搭建

一、序言 Java语言是美国Sun公司(Stanford University Network),在1995年推出的高级的编程语言。所谓编程语言,是 计算机的语言,人们可以使用编程语言对计算机下达命令,让计算机完成人们需要的功能。 Java Web主要是用Java技术来解决web领域的技术,需要运行在特定的web服务器上,Java Web是跨平台的,可以在不同的平台上进行部署运行。 二、安...

码上言 1万+

java教程_宝塔搭建JAVA生产级环境 搭建Java网站教程

宝塔搭建Java环境 java目前的主流的环境是tomcat的war包环境和springboot程序jar环境,还有一个微服务环境本质上也是基于这个springboot环境的,所以我们今天主要来讲解这两种环境的搭建,为了更好的操作文件,基于宝塔搭建!1.使用tomcat的war包环境1.首先使用安装Linux系统或者unix,等都是可以的,这里采用linux系统的发行版本centOS7版本2.登...

weixin_39991222的博客 2119
上一篇: 加固了就安全了?几个措施让你的 Android 应用更安全
下一篇: 个人开源库的一些更新,兼谈Jetpack和Kotlin给Android开发带来的变化
开发者如是说
博客等级 码龄10年 67粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值