最近在帮别人做微信小程序,需要一台服务器做后端,正好腾讯云有优惠,并且跟小程序都是一家子,所以选用了腾讯云服务器(CVM)
前言
微信小程序服务目标人群固定,短期内访问量不是很大,预测瞬时最高并发量120左右,所以云服务器选择了一款面向开发者的专惠套餐,1核/2G内存/1Mbps带宽/50G存储,操作系统CentOS7.6。完成在线实验任务,可升级到4G内存,完成Web业务验证任务,可升级到2M带宽。另外还有邀请好友免费续费活动,这个可能就比较难完成了。
小程序后端开发的是Java Web应用,在tomcat上运行,数据库选用PostgreSQL,并安装PostGIS插件用于地理位置计算。使用Nginx做代理,一是可以反向代理到tomcat,并且可配置负载均衡,二是可以直接代理静态资源文件。
所以罗列了一下需要安装及配置的内容:
1、JDK
2、Tomcat
3、PostgreSQL
4、PostGIS
5、Nginx
另外,微信小程序要求后端服务器必须通过htpps域名访问,并且必须ICP备案,所以域名申请和解析,ssl证书的申请,ICP备案这些都是必须的。索性腾讯云这方面的服务比较到位,去相应的页面操作即可,这里就不详述了。(备案周期比较长,建议域名申请后立即做备案,因为备案的时候根本不关心你的网站做没做好,有什么内容,而且备案时明确要求暂停或关闭域名解析的)
如果本地电脑系统是Windows,建议使用WinSCP软件连接云服务器,上传/下载文件很方便。
下面主要阐述一下服务器环境的搭建步骤及方法。
JDK的安装
选用yum的方式安装jdk比较简单方便,不需要配置环境变量,至少本人亲测没问题,搭配tomcat启动Web应用服务一切正常。
- 查找jdk版本。
yum search java|grep jdk
- 选择适合的版本进行安装(本例选择1.8版)。
yum install -y java-1.8.0-openjdk
- 验证,出现下图即算完成。
java -version
- 如果想配置环境变量,建议把devel一起安装。
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
- JDK默认安装路径/usr/lib/jvm,安装完成后该目录下应该有如下图所示的内容。
- 配置环境变量,在/etc/profile文件尾部添加如下代码。(如果不熟悉VI,比如我,建议使用WinSCP将profile文件下载到本地编辑后再上传)
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME CLASSPATH PATH
- 保存后执行
source /etc/profile
Tomcat的安装
- 添加用户组。
groupadd tomcat
- 添加一个用户tomcat 并分配到组tomcat,设置其home目录为/home/tomcat,并且这个用户为非登录用户。
useradd -s /bin/nologin -g tomcat -d /home/tomcat tomcat
- 进入https://tomcat.apache.org/download-90.cgi页面,选择Binary Distributions(二进制发行版)下的Core(核心)下的tar.gz的压缩文件,复制其下载地址,用
wget
命令在CentOS终端下载。
wget -c http://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.29/bin/apache-tomcat-9.0.29.tar.gz
- 把下载的内容解压到 /home/tomcat 里。
tar -zxvf apache-tomcat-9.0.29.tar.gz -C /home/tomcat --strip-components 1
-C 选项的作用是:指定需要解压到的目录。
--strip-components 1 提取下一级目录。
- 为 /home/tomcat/bin/catalina.sh 生成链接。
ln -s /home/tomcat/bin/catalina.sh /etc/init.d/tomcat
- 编辑 /etc/profile 将 /home/tomcat 目录添加到环境变量中。
export CATALINA_HOME=/home/tomcat
- 保存后执行
source /etc/profile
- 把目录/home/tomcat/的own权限分配置给tomcat组的tomcat用户。
chown -R tomcat:tomcat /home/tomcat/
- 修改/home/tomcat/webapps/manager/META-INF/context.xml文件,注释掉其中的Valve标签(非必须,如果想使用tomcat管理页面需设置)。
- 修改/home/tomcat/conf/tomcat-users.xml,增加如下配置(非必须,如果想使用tomcat管理页面需设置)。
- 现在就可以通过/etc/init.d/tomcat 来启动了,如下三种命令皆可,指定tomcat用户来启动,防止tomcat删除你整个硬盘里的东西(后一个-u参数一定要带,不然java web应用程序启动会报权限不足拒绝访问的错误,这是我遇到的一个很大的坑)
sudo -u tomcat /home/tomcat/bin/catalina.sh start -u -security
sudo -u tomcat /etc/init.d/tomcat start -u -security
sudo -u tomcat service tomcat start -u security
这里有个坑,CentOS非root用户不能启动1024以内的端口,所以如果tomcat使用80、443这样的端口,则必须用root用户启动tomcat,不能使用上述的tomcat用户启动,否则80、443不会被监听到。
换而言之,使用80、443端口,则上述安装过程中创建tomcat用户组/用户等的步骤都可以不做。
可以使用下述命令查看操作系统当前各端口的监听状态。
netstat -tunlp
- 停止tomcat服务使用下面的命令
sh /home/tomcat/bin/shutdown.sh
- 监控日志命令(Ctrl+C退出,实时监控可以用这个命令,如果想看得更全还是下载下来更好)
tail -f /home/tomcat/logs/catalina.out
- tomcat启动后,可以通过下面的命令来查看tomcat监听的端口,一般是8009:与其它http集成可能用到的端口;8080:web访问端口;8005:监听关闭tomcat的端口。
netstat -napt |grep java |grep LISTEN
- ssl的配置
1、将证书下载后解压缩,把其中tomcat文件夹下的 www.domain.com.jks 文件上传到 /home/tomcat 目录下;
2、修改 /homt/tomcat/conf/server.xml 文件:<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="443" /> <Connector port="443" protocol="HTTP/1.1" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" keystoreFile="www.domain.com.jks" keystorePass="40te94si4u5f20x" />
2.1、80端口的redirectPort修改成443,
2.2、新添加443端口的设置,其中keystoreFile的内容是上传的那个jks文件的文件名,可以是绝对路径也可以是相对路径,相对路径是相对于CATALINA_HOME的路径,keystorePass的内容是证书解压缩后tomcat目录里keystorePass.txt文件的内容;
3、重启tomcat即可。
- Tomcat9简单的安全设置
1、隐藏版本号
mkdir -p /home/tomcat/lib/org/apache/catalina/util
vi /home/tomcat/lib/org/apache/catalina/util/ServerInfo.properties 添加下面内容
server.info=version
然后重启tomcat就可以了
2、修改/home/tomcat/conf/server.xml 中<Server port="8005" shutdown="SHUTDOWN">这个配置中的port值及shutdown值;port指定的是指定Tomcat监听shutdown命令端口,shutdown指定终止Tomcat服务器运行时,发给Tomcat服务器的shutdown监听端口的字符串;为了安全起见。不要使用默认值;如修改成下面的内容
<Server port="8303" shutdown="god_bless_me_have_no_longer_bug">
记住一定要在你没有启动tomcat的情况修改
3、在自己的web应该中尽量替换默认的404,403,500页面
4、尽量在启动脚本后加-security 增加安全管理;如
/home/tomcat/bin/catalina.sh start -security
5、尽量不要用root用户启动tomcat(对于想用80、443端口,则必须root启动)
- 关于tomcat正常启动后,网站无法访问的排查办法。
1、确认域名解析是否正确;
2、安全组设置是否正确(要开放tomcat中设置的访问监听端口)。
3、确认端口是否被监听(非root用户启动tomcat后,80、443等端口就不会被监听);
4、确认网站是否完成ICP备案(不备案80、443端口无法访问,但用ip地址可以)。
重要的事情我只说一遍,上述第三和第四点是我遇到的最大的坑。
- tomcat项目部署的三种方式:
1、直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的一种Tomcat项目部署的方法,缺点是只能通过 http://www.domain.com/项目目录名 访问。
2、修改/home/tomcat/conf/server.xml,在<host>和</host>之间加入如下代码<Context docBase="newwebapp" path="/nwa" debug="0" reloadable="true" />
此时可以通过http://www.domain.com/nwa 访问,docBase是项目路径,可以是绝对路径,也可以是相对于Host中的appBase设置的目录的相对路径;path是访问路径,如果想让域名直接访问该项目,则path设置成"/"即可。
3、在 /home/tomcat/conf/Catalina/localhost 下新建一个nwa.xml文件(文件名即是访问路径,如果跟内容中的path不一致,tomcat还是会以文件名作为访问路径的,所以感觉Context里的path没什么用),编辑内容如下:<Context path="/nwa" docBase="newwebapp" debug="0" privileged="true" />
第二和第三种方法比较灵活。第三种方式如果想设置成根目录访问,则xml文件名必须叫ROOT.xml。
- 如果应用中有图片/文件上传功能,记得这几个方面需要考虑到:
1、Tomcat 以 tomcat 用户身份启动时,保存上传资源的目录一定要对tomcat赋予足够的操作权限。
chown -R tomcat:tomcat /home/webapps/
2、修改 Tomcat 安装根目录下的 /bin/catalina.sh 文件,将下面的代码普片段中的 UMASK 的值 0027 改成 0022 ,否则上传成功后,nginx 无法访问(不用nginx直接代理该资源文件时这个可以不设置)。
# Set UMASK unless it has been overridden if [ -z "$UMASK" ]; then UMASK="0027" fi umask $UMASK
3、nginx 默认允许客户端请求数据大小是1M,如果允许上传文件大小大于该数值,记得修改 nginx 的改项配置,否则请求在 nginx 这一层就会被拦下。
client_max_body_size 20M;
PostgreSQL
- 在官网(https://www.postgresql.org/download/linux/redhat/)选择数据库版本,操作系统版本等信息后,页面会自动生成安装各步骤的命令,照此安装即可。
- 上述步骤完成后,默认会创建一个名为postgres的linux登录用户,这里进行密码修改。
passwd postgres
- 编辑 /var/lib/pgsql/12/data/postgresql.conf 文件的远程连接信息,让所有计算机能访问到该测试数据库;去掉下图的#,修改localhost为*后保存(vi命令:wq)。
- 同样对 /var/lib/pgsql/12/data/pg_hba.conf 文件进行编辑;追加下图红框内的一行数据,修改黄框的内容后保存。
- 重启服务:
systemctl restart postgresql-12
- 用postgres账号登录centos服务器,并修改数据库用户密码(或者直接 su postgres 切换过去)
psql -U postgres
\password
用客户端连接测试即可。
PostgreSQL相关的补充:
1、别忘记安全组中开放5432端口,即便该数据库紧供同台服务器上的web应用以localhost方式访问,也需要开放5432端口,原因未知(懒得发工单问腾讯技术人员了,之前tomcat的问题已经被折磨疯了)。
- 自动备份数据库
在 /usr/pgsql-12/bin 目录下面创建 backup.sh 文件,内容如下:
#!/bin/bash
cur_time=$(date +%Y%m%d_%H_%M_%S);
/usr/pgsql-12/bin/pg_dump -h 127.0.0.1 -p 5432 -U postgres -F c -b -v -f /home/dbbackup/dbase_backup_$cur_time.dmp yourdbname;
同时创建目录 /home/dbbackup 作为备份文件存放路径。
启动cron服务:
# 查看服务状态
systemctl status crond
# 启动
systemctl start crond
# 停止
systemctl stop crond
# 重启
systemctl restart crond
# 重新加载
systemctl reload crond
开机自动启动cron服务
systemctl start crond.service
进入编辑模式
crontab -e
添加执行 backup.sh 任务
#每天2:30分执行
30 2 * * * /usr/pgsql-12/bin/backup.sh
保存退出
:wq
查看定时任务列表
crontab -l
查看定时任务执行日志
cat /var/log/cron
PostGIS
因为需要在数据库层面进行地理位置坐标之间的距离计算,所以需要安装PostgreSQL的一个相关的扩展PostGIS
查找合适的版本。
yum search postgis|grep postgis
- 因为之前安装的PostgreSQL的版本是12,所以选择12版对应的最新版postgis,即postgis30_12.x86_64。
yum install postgis30_12.x86_64
- 如果安装过程中出现缺少依赖包的问题,可以先执行下面语句安装依赖包。
rpm -ivh ftp://bo.mirror.garr.it/1/slc/centos/7.6.1810/extras/x86_64/Packages/epel-release-7-6.noarch.rpm
- 为始数据库可用PostGIS,需在该数据库上执行下列语句,我是用pgAdmin连数据库执行的,这里有个坑,该数据库一定要有public这个shema,因为要在public下创建一些表。
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology; # 这句不执行对于我的业务来说没影响,我只用距离计算这个功能。
- 测试,能正确返回数据表示成功能。
select ST_distance(ST_GeomFromText('POINT(121.2309 39.1823)', 4326)::geography, ST_GeomFromText('POINT(121.2319 39.1811)', 4326)::geography);
Nginx
- 使用 yum 命令安装 Nginx
yum install -y nginx
- 设置 Nginx 开机启动
systemctl enable nginx.service
- 启动Nginx
nginx
此时,访问 http://主机ip地址 可以看到Nginx的默认页。
配置文件 /etc/nginx/nginx.conf 里定义了80端口的默认配置,可以直接修改该文件,也可以在 /etc/nginx/conf.d 目录下新建 *.conf 文件进行自定义配置。我选择后一种方式,这样感觉更清晰些。
到 SSL 控制台下载证书文件,将解压缩后的 Nginx 文件夹下的两个文件上传至 /etc/nginx 目录下,
新建 ssl.conf 文件,编辑好后上传至 /etc/nginx/conf.d 目录,配置示例如下:
upstream tomcatweb {
server localhost:8443;
}
server {
listen 80;
server_name www.domain.com; # 改为绑定证书的域名
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name www.domain.com; # 改为绑定证书的域名
ssl_certificate 1_www.domain.com_bundle.crt; # 改为自己申请得到的 crt 文件的名称
ssl_certificate_key 2_www.domain.com.key; # 改为自己申请得到的 key 文件的名称
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
client_max_body_size 20M;
location / {
proxy_pass https://tomcatweb/yourapp/;
proxy_cookie_path /yourapp/ /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /yourapp/ {
proxy_pass https://tomcatweb/yourapp/;
proxy_cookie_path /yourapp/ /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /resource/ {
root /home/webapps/yourapp;
}
location /yourapp/resource/ {
root /home/webapps;
}
}
这个配置文件主要做了一下几件事:
1、监听80端口,重定向到443端口;
2、监听443端口,配置ssl证书,需要注意的是“ssl_certificate”和“ssl_certificate_key”这两个设置,可以使用绝对路径也可以使用相对路径,若是相对路径,则是相对 /etc/nginx 目录的路径;
3、/resource/ 下的文件都是静态文件,这里做了设置,nginx直接代理;
4、上例中的静态资源配置,如果访问地址是 https://www.domain.com/resource/test.jpg 则nginx会按照配置找 /home/webapps/yourapp/resource/test.jpg 文件,注意这里是把root的值和location的值拼在一起;
5、upstream 的配置,将来如果是多Tomcat服务器的话,直接在这里加新地址即可,可实现负载均衡;
6、注意upstream配置的命名,如果带下划线,写成tomcat_web,跳转到tomcat9时会报错”java.lang.IllegalArgumentException: The character [_] is never valid in a domain",Tomcat7好像不会,所以为了避免不必要的问题出现,这里就不要使用下划线命名了;
7、proxy_pass 如果是设置到某个具体的应用下(比如上例),则最后一定要加“/”这个符号,不加会有问题,至于为什么我没调查;
8、像上例这样反向代理到具体某个应用时,location /yourapp/ 这个一定要设置,不然应用内不的相对路径加载资源文件等会找不到(因为Nginx只设置跟路径解析,应用内部相对路径引用的文件地址会解析成www.domain.com/yourapp/yourapp/.)。
- 修改配置完成后,重启 nginx 服务
nginx -s reload
使用 https 协议访问你的域名, 如 https://www.domain.com 检查是否成功,如果地址栏出现绿色带
安全
字样的锁头标志,说明 SSL 配置成功。补充一点,有一次重启系统后,发现直接访问 tomcat 正常,但访问 nginx 返回502错误,查看 nginx 错误日志文件,发现报
connect() to [::1]:8080 failed (13: Permission denied) while connecting to upstream, client:
错误,解决方案是查看系统 httpd 配置,
getsebool -a | grep httpd
设置httpd可以连接到网络
setsebool httpd_can_network_connect on -P
写在最后
整个安装过程其实比较简单,除了PostgreSQL耗时有点长,其它软件安装速度很快。
配置上则需要看具体需求了,其实只使用Tomcat我觉得也完全可以,但这次用Nginx+Tomcat,算是一种尝试吧,主要考虑用Nginx实现动静分离,至于负载均衡暂时还用不上。
另外Nginx+Tomcat的方式,我这次是两边都采用https协议,其实也可以只Nginx实现https,而Tomcat仍旧使用http协议。
最后的最后,给新建网站的朋友一个建议,一定要先申请域名做ICP备案,备案周期真的比较长,不要像我这样万事俱备苦等审核结果。
后期补充
运维过程中需求变更,某个小程序页面有使用WebSocket的应用场景,简化开发及运维成本,选用Node.js构建了WebSocket服务器,接下来补充一下Node.js相关的环境搭建。
Node.js
- 添加 Node.js Yum 存储库
yum clean all && yum makecache fast
yum install -y gcc-c++ make
curl -sL https://rpm.nodesource.com/setup_12.x | sudo -E bash -
- 安装 Node.js (不进行上面的操作直接执行安装,只能安装到6.x版本)
yum install nodejs -y
- 安装 npm 包管理器
yum install npm -y
- 新建项目文件夹,比如/home/webapps/yourapp
mkdir /home/webapps/yourapp
- 进入新建的文件夹
cd /home/webapps/yourapp
- 初始化环境,成功后会生成 package.json 文件
npm init -y
- 因使用到了 ws 和 pg 两个第三方组件,所以需要顺次安装
npm install ws --save
npm install pg --save
将本地写好的代码文件上传
运行
node index.js
- 后台运行指令
/usr/bin/nohup /usr/bin/node /home/webapps/yourapp/index.js & >> /home/webapps/logs.txt
- 终止后台运行
先查看一下node的进程号
ps -aux|grep node
或者根据端口号查询
netstat -nap|grep 端口号
杀死进程
kill -9 进程号
- Nginx配置的修改
增加 upstream 的定义
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream nodews {
server localhost:3000;
}
增加location的定义
location /ws/ {
proxy_pass http://nodews/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
- 安全起见,可以不对外暴露websocket监听的3000端口