大概去年这个时候,某只三三打算把纸飞机服务器重新搞一下,当然结果是比以前好多了。嗯,以前的架构基本没法看……然而当时三三的文件已经不知道去哪里了,而且我在这一年折腾的过程中,又发现了一些别的问题。
纸飞机服务器是几年前买的小主机,配置挺低,尤其是硬盘太小。其次,学校的网络环境实在太差,像微信后台这样的项目如果放到我们自己的服务器中,延迟可以达到五分钟,不知道是什么原因,所以只能放到SAE上了。纸飞机只有一个域名:my.nuaa.edu.cn
,信息中心给开放的端口只有两个:22
和80
,而前者用来做校内ssh
用,也就是说其实只有一个80端口可用。
前辈们写的代码大多数停留在“可用”的阶段,没有太多重构,静态数据没有分离,甚至有时会出现两个项目相互影响的情况。备份脚本已经好久没人动过了,而且纸飞机是七年多之前从论坛起家,针对discuz
的备份脚本已经无法适应目前的需求。因此,结合实际情况,我又自己YY出了一套东西,应该比现在的好一点。
好了言归正传。
这次我们的主角是CentOS7,其实本来去年就打算换7的,然而当时我们比较保守,认为7相对于6的变化实在太大(例如连ifconfig
和iptables
都换掉了)因此没有实现。这次我准备好好研究一下。
1. 安装CentOS7 Minimal
这个就不多说了,官网下镜像然后安装。
2. 配置网络
有了网络,什么都好说!首先先看一下服务器网卡的名称。由于CentOS7改了命名机制,有线网卡并不是用eth0
、eth1
作为名称了。
ip addr show
看到下面有那么一行:
2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
心里想,虽然我用的是虚拟机,但是这网卡名称eno16777736
也太特么长了吧!我一边说着卧槽,一边输入了如下指令:
vi /etc/sysconfig/network-scripts/ifcfg-eno16777736
首先ONBOOT=yes
设置开机自动配置,然后将BOOTPROTO=dhcp
等号右边换成static
,然后在下面添加如下几句话(xxx是我故意隐去的数字):
IPADDR=222.192.100.21 PREFIX=xxx GATEWAY=222.192.xxx.xxx DNS1=218.104.80.77 DNS2=222.119.64.123
然后用一句ifup eno16777736
把网卡带起来,一句systemctl restart network
,于是就可以上网啦!
3. 设置hostname
这个没什么好说的,直接执行如下指令:
echo "my.nuaa.edu.cn" > /etc/hostname
4. 升级系统
这个也没什么好说的,毕竟CentOS7已经出了快半年了,肯定有一些包被更新了。执行如下指令:
yum -y upgrade
当然,一般不要用-y
选项,有个确认的步骤心里还是比较舒坦的。
5. 添加第三方软件源
其实下载源码编译安装也可以,但是我比较懒,因此喜欢用yum来装软件。这里需要添加一些额外的软件源,例如epel
、community
、remi
、nginx
等。
# epel yum install epel-release # community rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm # remi rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm # nginx rpm --import http://nginx.org/keys/nginx_signing.key rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
6. 禁用selinux,安装firewall
selinux
这玩意从一开始就一直妨碍我,如果启用,访问/var/www
以外的文件都会提示403错误,于是就把它禁用掉好了,不知道禁用之后会有什么风险。
vi /etc/sysconfig/selinux
将其中的SELINUX=enforcing
等号右边改为disabled
即可。
然后总得有点什么防护措施吧,之前用的是iptables
,在CentOS7中推荐使用firewall
,但是我下载的镜像中好像没有这个程序,于是就通过yum
来装啦!
yum -y install firewalld systemctl enable firewalld systemctl start firewalld
firewall
默认的zone
是public
,也就是说,除了允许的服务和端口以外,丢弃掉其它的连接。看了一下配置文件,发现ssh
服务默认是允许通过的,于是就放心了。
7. 安装nginx并配置防火墙规则
直接输入如下命令:
yum install nginx systemctl enable nginx
装完之后需要在firewall
中开启对应的端口。由于纸飞机对外只有80
端口,所以直接添加一个规则即可:
firewall-cmd --zone=public --add-port=80/tcp --permanent
8. 安装/配置MariaDB
MariaDB
是一个新的数据库程序,但是操作起来跟MySQL
几乎完全一样。在几年前Archlinux
就用MariaDB
替代了MySQL
作为默认的数据库程序。
yum install mariadb-server systemctl enable mariadb systemctl start mariadb
然后设置一下MariaDB
的安全配置。
mysql_secure_installation
在这个步骤中,我们会设置root账户的
密码、删除匿名用户、锁定远程访问、删除test表等操作。
9. 安装/配置PHP
CentOS下面的PHP
一直是个难题,因为目前PHP
的版本是7.0
,上一个稳定版是5.6
,然而CentOS7下面的官方版本还是5.4
,CentOS6下面的甚至是5.3
!后者早就过期了,前者也快要停止支持了。还好有一个叫remi
的软件源帮了大忙。remi
源在刚才的步骤中已经添加过了,因此我们可以直接用yum
来安装5.6
版的PHP
。
yum -y install php56 php56-php-fpm php56-php-gd php56-php-mbstring php56-php-mcrypt php56-php-pdo php56-php-xml php56-php-pecl-memcache
当然,有的项目还需要其它PHP
的扩展,例如如果需要tidy
扩展的话,可以直接输入:
yum -y install php56-php-tidy
然后设置php-fpm
服务为开机自动启动,并启动它:
systemctl enable php-fpm systemctl start php-fpm
顺便提一下,nginx
对PHP
的支持跟apache
是有区别的,前者是两个服务(nginx
和php-fpm
),任务基本对半分,后者基本上apache
占了大头(mod_php
模块),PHP
只有做解析的份儿。
然后对PHP
做一下设置,在/etc/php.ini
中添加如下两行(有的服务器可能配置文件不在这里,可以用php56 --ini
命令来查看,第一行就有):
cgi.fix_pathinfo=0 date.timezone="Asia/Shanghai"
其中第一行是避免所谓的“nginx文件名解析漏洞”——事实上,这跟nginx
并没毛线关系,是php-fpm
的一个特性:例如在解析http://my.nuaa.edu.cn/foo.jpg/a.php/b.php/c.php
的时候,nginx
只是老老实实将请求转发到php-fpm
中,然后php-fpm
会依次尝试解析以下文件:
/foo.jpg/a.php/b.php/c.php /foo.jpg/a.php/b.php /foo.jpg/a.php /foo.jpg
如果都没有,则返回404错误。为何上文强调“解析”两个字?因为如果foo.jpg
是一段恶意代码,那么就会被php-fpm
解析到,就会发生一些不好的事情。(好像比较新的php-fpm
已经把它禁掉了。)
第二行则是设置默认时区,没什么好说的。
10. 配置服务器
由于CentOS7在用yum
装PHP
的时候会附带上apache
,于是先把后者禁掉:
systemctl disable httpd
然后配置nginx
的设置文件。纸飞机目前有discuz
、evaluation
、mall
、sso
、wiki
等十六个项目,由于历史原因,discuz
必须放在网站根目录/data/www
中;由于只有一个域名和一个端口,所以mall
等项目的网址必须是http://my.nuaa.edu.cn/mall/
。
当前纸飞机的服务器软件用的是apache
,解决方案是在配置文件里设置DocumentRoot
为/data/httpd/discuz
,然后给每一个项目设置一个Alias
,例如Alias /mall /data/httpd/mall
,然而这样太麻烦了。
折腾了好久,最终我写出了这样一份配置文件:
这是/etc/nginx/nginx.conf
:
http { include /etc/nginx/mime.types; default_type text/html; # 防止暴露服务器软件信息 server_tokens off; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; keepalive_timeout 65; # 开启压缩 gzip on; include /etc/nginx/conf.d/*.conf; # 默认只能上传1M的文件,这里改成30M client_max_body_size 30m; }
这是/etc/nginx/conf.d/mynuaa.conf
:
server { listen 80; server_name my.nuaa.edu.cn; root /data/www; index index.php index.html index.htm; # 允许解析符号链接 disable_symlinks off; # GZip相关设置,防止有的文件压缩之后比原来还大 gzip_min_length 1k; gzip_comp_level 2; gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml; location /office { # 办公系统的网址,被我隐藏掉了 proxy_pass http://xxx.sinaapp.com/; } # 禁止访问所有隐藏文件 location ~ /\. { deny all; } location / { if (-e /data/www/discuz$uri) { root /data/www/discuz; } # Discuz!的重写规则 rewrite ^([^\.]*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last; rewrite ^([^\.]*)/article-([0-9]+)-([0-9]+)\.html$ $1/portal.php?mod=view&aid=$2&page=$3 last; rewrite ^([^\.]*)/forum-(\w+)-([0-9]+)\.html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last; rewrite ^([^\.]*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last; rewrite ^([^\.]*)/group-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=group&fid=$2&page=$3 last; rewrite ^([^\.]*)/space-(username|uid)-(.+)\.html$ $1/home.php?mod=space&$2=$3 last; rewrite ^([^\.]*)/blog-([0-9]+)-([0-9]+)\.html$ $1/home.php?mod=space&uid=$2&do=blog&id=$3 last; rewrite ^([^\.]*)/(fid|tid)-([0-9]+)\.html$ $1/index.php?action=$2&value=$3 last; rewrite ^([^\.]*)/([a-z]+[a-z0-9_]*)-([a-z0-9_\-]+)\.html$ $1/plugin.php?id=$2:$3 last; location ~ \.php { set $my_root "/data/www"; if (-e /data/www/discuz$uri) { set $my_root "/data/www/discuz"; } try_files $uri =404; fastcgi_pass unix:/dev/shm/php-fpm.sock; fastcgi_param SCRIPT_FILENAME $my_root$fastcgi_script_name; include fastcgi_params; } } location /evaluation { alias /data/www/evaluation/public/; # Laravel的重写规则 if (!-f $request_filename) { rewrite ^(.*)$ /evaluation/index.php?$query_string; } location ~ \.php { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/dev/shm/php-fpm.sock; fastcgi_param SCRIPT_FILENAME /data/www/evaluation/public/index.php; include fastcgi_params; } } access_log /var/log/nginx/access.log main; error_page 404 /404.html; error_page 500 502 503 504 /50x.html; }
不知道有没有什么潜在的问题,还请大神们轻喷…… Update 1.6:果然有问题……已修改。
通过如下命令来确定服务器的CPU核数:
grep processor /proc/cpuinfo | wc -l
结果是8核,于是在/etc/nginx/nginx.conf
中修改:
worker_processes 8;
最后当然是启动nginx
服务:
systemctl start nginx
至此,运行环境已经配置完毕。接下来就是配置纸飞机的各个应用了。
11. 安装Git/配置webhook/部署应用
Git
用来管理代码。
yum -y install git
由于我们的代码都托管在Coding.net上,之前在上面设置了webhook以及部署公钥,因此需要将原来服务器的~/.ssh/id_rsa
和~/.ssh/id_rsa.pub
两个文件复制过来,这样就可以继续使用webhook功能啦!如何复制就不贴代码了。
然后将之前写好的webhook项目手动clone到/data/www
目录下:
cd /data/www && sudo -u nginx git clone [email protected]:Click_04/webhooks.git
这是一个私有项目,如果之前的id_rsa文件没问题的话,此时应该成功clone下来了。然后我们将其中的config.sample.php
复制一份,并重命名为config.php
:
cd webhooks && sudo -u nginx cp config.sample.php config.php
然后按照项目说明中的描述,输入网址,就可以clone项目以及pull更新啦!纸飞机有那么多项目,都clone下来还是挺麻烦的呢!
最后是每个项目的构建,例如五四评优用到了url rewrite
的规则,需要在nginx
的站点配置文件中添加如下几句:
location /evaluation { try_files $uri $uri/ /index.php?$query_string; }
当然,有的项目也需要用到Composer
,可以通过如下方式安装:
cd /tmp && wget http://install.phpcomposer.com/installer php56 ./installer -- --install-dir=/usr/bin --filename=composer
顺便吐槽一句:这下载速度可真够慢的。
12. 导入应用数据
刚才只是把代码clone下来了,现在需要将应用的数据导入进来。安全起见,每个应用都是独立的数据库,并分配独立的账号来管理,保持每个账号权限最小化。在数据库中折腾一番之后终于好了。然后将服务器关停之前最后一次mysqldump
生成的数据文件导入即可。
至于与代码无关的静态文件,在之前我已经将它们与代码分离开了,所以并不用担心。所有应用的静态文件都储存在/storage/app
目录中。同时在/storage/lib
目录中还有一个所有项目公用的静态库集合,例如jquery、mui等,这个也可以通过git仓库来随时更新。
13. 安装OneAPM监控
这个没啥好说的,按照OneAPM的操作来就是了。不过值得注意的一点是,需要先将/usr/bin/php
替换为php56
,然后填写PHP配置文件路径的时候填写/opt/remi/php56/root/etc/php.ini
,否则会导致安装不成功。
14. 计划任务:数据库备份
目前的想法是:每周完整备份,每小时增量备份。使用Xtrabackup
作为备份程序。如果服务器性能不太好的话,就需要添加对硬盘的IO限制。首先安装Xtrabackup
:
yum install http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm yum install percona-xtrabackup-22
然后编写备份脚本:
#!/bin/bash # database full backup # author: rex # using xtrabackup USERNAME="root" PASSWORD="root" STORPATH="/backup/mysql" # full backup innobackupex --user=$USERNAME --password=$PASSWORD --no-timestamp $STORPATH/$(date +%Y%m%d)-full --throttle=80 # first incremental backup LASTBACKUPDIR=$(date +%Y%m%d%H%M%S) innobackupex --incremental $STORPATH/$LASTBACKUPDIR --no-timestamp --incremental-basedir=$STORPATH/$(date +%Y%m%d)-full --user=$USERNAME --password=$PASSWORD --defaults-file=/etc/my.cnf --throttle=80 # print to $STORPATH/lastbackupdir echo $LASTBACKUPDIR > $STORPATH/lastbackupdir
这是增量备份脚本:
#!/bin/bash # database incremental backup # author: rex # using xtrabackup USERNAME="root" PASSWORD="root" STORPATH="/backup/mysql" if [ ! -e $STORPATH/lastbackupdir ]; then exit 0 fi LASTBACKUPDIR=$(date +%Y%m%d%H%M%S) innobackupex --incremental $STORPATH/$LASTBACKUPDIR --no-timestamp --incremental-basedir=$STORPATH/$(cat $STORPATH/lastbackupdir) --user=$USERNAME --password=$PASSWORD --defaults-file=/etc/my.cnf echo $LASTBACKUPDIR > $STORPATH/lastbackupdir
我把这两个脚本放到了/maintain/crontan
文件夹下,系统升级等计划任务也可以写成.sh
文件存放到这里,这样可以达到定期更新系统的效果。
关于计划任务,配置在/etc/crontab
这个文件中。
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # For details see man 4 crontabs # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed 30 * * * * root /maintain/crontab/dbincbackup 0 0 * * 1 root /maintain/crontab/dbfullbackup * * * * * root /maintain/crontab/dellocalroute
参考文章:
http://www.tecmint.com/things-to-do-after-minimal-rhel-centos-7-installation/
https://www.linux.cn/article-4314-1.html
https://www.percona.com/doc/percona-xtrabackup/2.2/installation/yum_repo.html
https://www.centos.bz/2013/09/percona-xtrabackup-mysql-backup/