前言

现在很多朋友都了解或者已经在使用 LNMP 架构,一般可以理解为 Linux Shell 为 CentOS/RadHat/Fedora/Debian/Ubuntu / 等平台安装 LNMP(Nginx/MySQL/PHP),LNMPA(Nginx/MySQL/PHP/Apache),LAMP(Apache/MySQL/PHP)等类似的开发或生产环境。我自己是从 SuSE/Oracle 商业化环境走出来的,对于开源的部署方案也是在一点一点摸索,我相信其中也必然包含某些坑爹的配置。这篇文章较为详细的描述了基于 LTMP 架构的部署过程,之后会再考虑独立各个模块分享细节和技巧,如果大家有更合适的配置实践手册欢迎一起分享,文章中的错误和改进点也请帮忙指点下哈。

LTMP(CentOS/Tengine/MySQL/PHP)


更新历史

2015 年 08 月 14 日 - 更新 GitHub 自动部署源码和安装包
2015 年 08 月 04 日 - 初稿

阅读原文 - https://liaojiaxin158.github.io/post/ltmp/

扩展阅读

CentOS - http://www.centos.org/
Tengine - http://tengine.taobao.org/
Nginx - http://nginx.org/en/docs/
MySQL - http://www.mysql.com/
PHP - http://php.net/
LTMP 索引 - https://liaojiaxin158.github.io/index/#LTMP


LTMP 版本

  1. CentOS_6.5_64
  2. Tengine-2.1.0
  3. MySQL_5.6.25
  4. PHP_5.5.27
  5. Apache_2.2.31(酱油)

准备工作

如果允许公网访问会方便很多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# 优化 History 历史记录 
vi /etc/bashrc

# 设置保存历史命令的文件大小
export HISTFILESIZE=1000000000
# 保存历史命令条数
export HISTSIZE=1000000
# 实时记录历史命令,默认只有在用户退出之后才会统一记录,很容易造成多个用户间的相互覆盖。
export PROMPT_COMMAND="history -a"
# 记录每条历史命令的执行时间
export HISTTIMEFORMAT="%Y-%m-%d_%H:%M:%S"

# 设置时区(可选)
rm -rf /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 禁用 NetworkManager(可选)
/etc/init.d/NetworkManager stop
chkconfig NetworkManager off
/etc/init.d/network restart

# 关闭 iptables(可选)
/etc/init.d/iptables stop
chkconfig iptables off

# 设置 dns(可选)
echo "nameserver 114.114.114.114" > /etc/resolv.conf

# 关闭 maildrop
#cd /var/spool/postfix/maildrop;ls | xargs rm -rf;
sed 's/MAILTO=root/MAILTO=""/g' /etc/crontab
service crond restart

# 关闭 selinux
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config


# 文件打开数量,
echo ulimit -SHn 65535 >> /etc/profile
source /etc/profile

# 修改最大进程和最大文件打开数限制
vi /etc/security/limits.conf
* soft nproc 11000
* hard nproc 11000
* soft nofile 655350
* hard nofile 655350

sed -i -e '/# End of file/i\* soft nofile 65535\n* hard nofile 65535' /etc/security/limits.conf

# 优化 TCP
vi /etc/sysctl.conf

# 禁用包过滤功能
net.ipv4.ip_forward = 0
# 启用源路由核查功能
net.ipv4.conf.default.rp_filter = 1
# 禁用所有 IP 源路由
net.ipv4.conf.default.accept_source_route = 0
# 使用 sysrq 组合键是了解系统目前运行情况,为安全起见设为 0 关闭
kernel.sysrq = 0
# 控制 core 文件的文件名是否添加 pid 作为扩展
kernel.core_uses_pid = 1
# 开启 SYN Cookies,当出现 SYN 等待队列溢出时,启用 cookies 来处理
net.ipv4.tcp_syncookies = 1
# 每个消息队列的大小(单位:字节)限制
kernel.msgmnb = 65536
# 整个系统最大消息队列数量限制
kernel.msgmax = 65536
# 单个共享内存段的大小(单位:字节)限制,计算公式 64G*1024*1024*1024(字节)
kernel.shmmax = 68719476736
# 所有内存大小(单位:页,1 页 = 4Kb),计算公式 16G*1024*1024*1024/4KB(页)
kernel.shmall = 4294967296
#timewait 的数量,默认是 180000
net.ipv4.tcp_max_tw_buckets = 6000
# 开启有选择的应答
net.ipv4.tcp_sack = 1
# 支持更大的 TCP 窗口. 如果 TCP 窗口最大超过 65535(64K), 必须设置该数值为 1
net.ipv4.tcp_window_scaling = 1
#TCP 读 buffer
net.ipv4.tcp_rmem = 4096 131072 1048576
#TCP 写 buffer
net.ipv4.tcp_wmem = 4096 131072 1048576
# 为 TCP socket 预留用于发送缓冲的内存默认值(单位:字节)
net.core.wmem_default = 8388608
# 为 TCP socket 预留用于发送缓冲的内存最大值(单位:字节)
net.core.wmem_max = 16777216
# 为 TCP socket 预留用于接收缓冲的内存默认值(单位:字节)
net.core.rmem_default = 8388608
# 为 TCP socket 预留用于接收缓冲的内存最大值(单位:字节)
net.core.rmem_max = 16777216
# 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog = 262144
#web 应用中 listen 函数的 backlog 默认会给我们内核参数的 net.core.somaxconn 限制到 128,而 nginx 定义的 NGX_LISTEN_BACKLOG 默认为 511,所以有必要调整这个值
net.core.somaxconn = 262144
# 系统中最多有多少个 TCP 套接字不被关联到任何一个用户文件句柄上。这个限制仅仅是为了防止简单的 DoS 攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)
net.ipv4.tcp_max_orphans = 3276800
# 记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有 128M 内存的系统而言,缺省值是 1024,小内存的系统则是 128
net.ipv4.tcp_max_syn_backlog = 262144
# 时间戳可以避免序列号的卷绕。一个 1Gbps 的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常” 的数据包。这里需要将其关掉
net.ipv4.tcp_timestamps = 0
# 为了打开对端的连接,内核需要发送一个 SYN 并附带一个回应前面一个 SYN 的 ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送 SYN+ACK 包的数量
net.ipv4.tcp_synack_retries = 1
# 在内核放弃建立连接之前发送 SYN 包的数量
net.ipv4.tcp_syn_retries = 1
# 开启 TCP 连接中 time_wait sockets 的快速回收
net.ipv4.tcp_tw_recycle = 1
# 开启 TCP 连接复用功能,允许将 time_wait sockets 重新用于新的 TCP 连接(主要针对 time_wait 连接)
net.ipv4.tcp_tw_reuse = 1
#1st 低于此值, TCP 没有内存压力, 2nd 进入内存压力阶段, 3rdTCP 拒绝分配 socket(单位:内存页)
net.ipv4.tcp_mem = 94500000 915000000 927000000
# 如果套接字由本端要求关闭,这个参数决定了它保持在 FIN-WAIT-2 状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是 60 秒。2.2 内核的通常值是 180 秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻载的 WEB 服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2 的危险性比 FIN-WAIT-1 要小,因为它最多只能吃掉 1.5K 内存,但是它们的生存期长些。
net.ipv4.tcp_fin_timeout = 15
# 表示当 keepalive 起用的时候,TCP 发送 keepalive 消息的频度(单位:秒)
net.ipv4.tcp_keepalive_time = 30
# 对外连接端口范围
net.ipv4.ip_local_port_range = 2048 65000
# 表示文件句柄的最大数量
fs.file-max = 102400

# 云主机上的优化

# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and
# sysctl.conf(5) for more details.

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel

# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

# Controls the default maxmimum size of a mesage queue
kernel.msgmnb = 65536

# Controls the maximum size of a message, in bytes
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736

# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.netfilter.nf_conntrack_max = 1000000
kernel.unknown_nmi_panic = 0
kernel.sysrq = 0
fs.file-max = 1000000
vm.swappiness = 10
fs.inotify.max_user_watches = 10000000
net.core.wmem_max = 327679
net.core.rmem_max = 327679
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

/sbin/sysctl -p

# 自动选择最快的 yum 源
yum -y install yum-fastestmirror

# 移除系统自带的 rpm 包的 http mysql php
#yum remove httpd* php*
yum remove httpd mysql mysql-server php php-cli php-common php-devel php-gd -y

# 升级基础库
yum install -y wget gcc gcc-c++ openssl* curl curl-devel libxml2 libxml2-devel glibc glibc-devel glib2 glib2-devel gd gd2 gd-devel gd2-devel libaio autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel

#yum 安装基础必备环境包,可以先将 yum 源更换为阿里云的源
阿里:http://mirrors.aliyun.com/
搜狐:http://mirrors.sohu.com/
网易:http://mirrors.163.com/

# 备份原先的 yum 源信息
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

# 从阿里云镜像站下载 centos6 的 repo
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

# 最后 yum 重新生成缓存
yum makecache

#yum 安装软件包(可选)
yum -y install tar zip unzip openssl* gd gd-devel gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel openldap-clients openldap-servers make libmcrypt libmcrypt-devel fontconfig fontconfig-devel libXpm* libtool* libxml2 libxml2-devel t1lib t1lib-devel



# 定义目录结构,下载安装包
mkdir -p /app/{local,data}
cd /app/local

#PCRE - Perl Compatible Regular Expressions
wget "ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.37.tar.gz"
#Tengine
wget "http://tengine.taobao.org/download/tengine-2.1.0.tar.gz"
#MySQL
wget "https://downloads.mariadb.com/archives/mysql-5.6/mysql-5.6.25-linux-glibc2.5-x86_64.tar.gz"
#PHP
wget "http://cn2.php.net/distributions/php-5.6.11.tar.gz"
#Mhash
wget "http://downloads.sourceforge.net/mhash/mhash-0.9.9.9.tar.gz"
#libmcrypt
wget "http://downloads.sourceforge.net/mcrypt/libmcrypt-2.5.8.tar.gz"
#Mcrypt
wget "http://downloads.sourceforge.net/mcrypt/mcrypt-2.6.8.tar.gz"

配置 Tengine

安装 PCRE

1
2
3
4
5
tar zxvf pcre-8.37.tar.gz
cd pcre-8.37
./configure
make && make install
cd ../

安装 Tengine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加 www 用户和组
groupadd www
useradd -g www www
# 安装 Tengine
tar zxvf tengine-2.1.0.tar.gz
cd tengine-2.1.0

./configure --user=www --group=www \
--prefix=/app/local/nginx \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre=/app/local/pcre-8.37

make && make install
cd ../

配置 Nginx

Nginx 配置文件的优化很重要,理解每一步的意义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# 修改 nginx.conf
vi /app/local/nginx/conf/nginx.conf

# 用户和用户组
user www www;
# 工作进程,一般可以按 CPU 核数设定
worker_processes auto;
worker_cpu_affinity auto;
# 全局错误日志级别
# [ debug | info | notice | warn | error | crit ]
error_log logs/error.log error;
#PID 文件位置
pid logs/nginx.pid;
# 更改 worker 进程的最大打开文件数限制,避免 "too many open files"
worker_rlimit_nofile 65535;

#events 事件指令是设定 Nginx 的工作模式及连接数上限
events{
#epoll 是 Linux 首选的高效工作模式
use epoll;
# 告诉 nginx 收到一个新连接通知后接受尽可能多的连接
multi_accept on;
# 用于定义 Nginx 每个进程的最大连接数
worker_connections 65536;
}

#HTTP 模块控制着 nginx http 处理的所有核心特性
http {
include mime.types;
# 设置文件使用的默认的 MIME-type
default_type application/octet-stream;


# 对日志格式的设定,main 为日志格式别名
log_format main '$remote_addr - $remote_user [$time_local]"$request"'
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent""$http_x_forwarded_for"';
# 设置 nginx 是否将存储访问日志。关闭这个选项可以让读取磁盘 IO 操作更快
access_log off;
# access_log logs/access.log main buffer=16k;

# 开启 gzip 压缩,实时压缩输出数据流
gzip on;
# 设置 IE6 或者更低版本禁用 gzip 功能
gzip_disable "MSIE [1-6]\.";
# 前端的缓存服务器缓存经过 gzip 压缩的页面
gzip_vary on;
# 允许压缩基于请求和响应的响应流
gzip_proxied any;
# 设置数据的压缩等级
gzip_comp_level 4;
# 设置对数据启用压缩的最少字节数
gzip_min_length 1k;
# 表示申请 16 个单位为 64K 的内存作为压缩结果流缓存
gzip_buffers 16 64k;
# 用于设置识别 HTTP 协议版本
gzip_http_version 1.1;
# 用来指定压缩的类型
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;


# 打开缓存的同时也指定了缓存最大数目,以及缓存的时间
open_file_cache max=200000 inactive=20s;
# 在 open_file_cache 中指定检测正确信息的间隔时间
open_file_cache_valid 30s;
# 定义了 open_file_cache 中指令参数不活动时间期间里最小的文件数
open_file_cache_min_uses 2;
# 指定了当搜索一个文件时是否缓存错误信息,也包括再次给配置中添加文件
open_file_cache_errors on;

# 设置允许客户端请求的最大的单个文件字节数
client_max_body_size 30M;
# 设置客户端请求主体读取超时时间
client_body_timeout 10;
# 设置客户端请求头读取超时时间
client_header_timeout 10;
# 指定来自客户端请求头的 headerbuffer 大小
client_header_buffer_size 32k;
# 设置客户端连接保持活动的超时时间
keepalive_timeout 60;
# 关闭不响应的客户端连接
reset_timedout_connection on;
# 设置响应客户端的超时时间
send_timeout 10;
# 开启高效文件传输模式
sendfile on;
# 告诉 nginx 在一个数据包里发送所有头文件,而不一个接一个的发送
tcp_nopush on;
# 告诉 nginx 不要缓存数据,而是一段一段的发送
tcp_nodelay on;
# 设置用于保存各种 key(比如当前连接数)的共享内存的参数
limit_conn_zone $binary_remote_addr zone=addr:5m;
# 给定的 key 设置最大连接数,允许每一个 IP 地址最多同时打开有 100 个连接
limit_conn addr 100;

#FastCGI 相关参数是为了改善网站的性能:减少资源占用,提高访问速度
fastcgi_buffers 256 16k;
fastcgi_buffer_size 128k;
fastcgi_connect_timeout 3s;
fastcgi_send_timeout 120s;
fastcgi_read_timeout 120s;
server_names_hash_bucket_size 128;
# 不在 error_log 中记录不存在的错误
log_not_found off;
# 关闭在错误页面中的 nginx 版本数字,提高安全性
#server_tag Apache;
server_tokens off;
#tengine
server_tag off;
server_info off;

# 添加虚拟主机的配置文件
include vhosts/*.conf;

# 负载均衡配置(暂时略过)
#upstream test.com

# 设定虚拟主机配置
server {
# 侦听 80 端口
listen 80;
# 定义使用 localhost 访问
server_name localhost;
# 定义首页索引文件的名称
index index.html index.htm index.php;
# 定义服务器的默认网站根目录位置
root /app/data/localhost/;

# 定义错误提示页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

#PHP 脚本请求全部转发到 FastCGI 处理. 使用 FastCGI 默认配置.
location ~ .*\.(php|php5)?$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}

# 静态文件
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ico)$
{
# 过期 30 天,频繁更新可设置小一点
expires 30d;
}

location ~ .*\.(js|css)?$
{
# 过期 1 小时,不更新可设置大一些
expires 1h;
}
# 禁止访问
location ~ /\. {
deny all;
}
}
}

简化配置文件
vi /app/local/nginx/conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

user www www;
worker_processes auto;
worker_cpu_affinity auto;

error_log logs/error.log crit;
pid logs/nginx.pid;

worker_rlimit_nofile 51200;
events
{
use epoll;
multi_accept on;
worker_connections 51200;
}

http
{
include mime.types;
default_type application/octet-stream;

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 off;
#access_log logs/access.log main buffer=16k;

server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50M;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60;
server_tokens off;
server_tag off;
server_info off;

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;

#gzip on;
#gzip_min_length 1k;
#gzip_buffers 4 16k;
#gzip_http_version 1.1;
#gzip_comp_level 5;
#gzip_types text/plain application/x-javascript text/css application/xml;
#gzip_vary on;

include vhosts/*.conf;
}

分离 server 写入 vhosts
mkdir -p /app/local/nginx/conf/vhosts/
vi /app/local/nginx/conf/vhosts/localhost.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
server {
listen 80;
server_name localhost;
index index.php index.html index.htm;
access_log logs/localhost.log main;

root /app/data/localhost/;

location / {
index index.php index.html index.htm;
}

#error_page 404 /404.html;
#error_page 500 502 503 504 /50x.html;

location = /50x.html {
root html;
}

location ~ .*\.(php|php5)?$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi.conf;
}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ico)$
{
expires 30d;
}

location ~ .*\.(js|css)?$
{
expires 1h;
}

location ~ /\. {
deny all;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 检查语法
/app/local/nginx/sbin/nginx -t
# ./nginx -t
the configuration file /app/local/nginx/conf/nginx.conf syntax is ok
configuration file /app/local/nginx/conf/nginx.conf test is successful

# 测试用例
mkdir -p /app/data/localhost
chmod +w /app/data/localhost
echo "<?php phpinfo();?>" > /app/data/localhost/phpinfo.php
chown -R www:www /app/data/localhost

# 设置 nginx 系统变量
echo 'export PATH=$PATH:/app/local/nginx/sbin'>>/etc/profile && source /etc/profile

# 测试访问
curl -I http://localhost

HTTP/1.1 200 OK
Server: Tengine/2.1.0
Date: Mon, 27 Jul 2015 06:42:25 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.6.11

添加 Tengine 到服务

配置服务后便于统一管理
vi /etc/rc.d/init.d/nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/bin/sh

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

nginx="/app/local/nginx/sbin/nginx"
prog=$(basename $nginx)

NGINX_CONF_FILE="/app/local/nginx/conf/nginx.conf"

[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx

lockfile=/var/lock/subsys/nginx

make_dirs() {
# make required directories
user=`$nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
if [ -z "`grep $user /etc/passwd`" ]; then
useradd -M -s /bin/nologin $user
fi
options=`$nginx -V 2>&1 | grep 'configure arguments:'`
for opt in $options; do
if [ `echo $opt | grep '.*-temp-path'` ]; then
value=`echo $opt | cut -d "=" -f 2`
if [ ! -d "$value" ]; then
# echo "creating" $value
mkdir -p $value && chown -R $user $value
fi
fi
done
}

start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog:"
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}

stop() {
echo -n $"Stopping $prog:"
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}

restart() {
configtest || return $?
stop
sleep 1
start
}

reload() {
configtest || return $?
echo -n $"Reloading $prog:"
killproc $nginx -HUP
RETVAL=$?
echo
}

force_reload() {
restart
}

configtest() {
$nginx -t -c $NGINX_CONF_FILE
}

rh_status() {
status $prog
}

rh_status_q() {
rh_status >/dev/null 2>&1
}

case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
1
2
3
4
# 修改执行权限
chmod +x /etc/init.d/nginx
ulimit -SHn 65535
service nginx start

安装 MySQL

注意目录和字符集等配置文件,推荐使用 InnoDB 作为存储引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 解压 mysql
mkdir -p /app/local/mysql
tar zxvf mysql-5.6.25-linux-glibc2.5-x86_64.tar.gz
mv mysql-5.6.25-linux-glibc2.5-x86_64/* /app/local/mysql
# 增加 mysql 用户组
groupadd mysql
useradd -g mysql mysql
mkdir -p /app/data/mysql/data/
mkdir -p /app/data/mysql/binlog/
mkdir -p /app/data/mysql/relaylog/
chown -R mysql:mysql /app/data/mysql/
# 安装 mysql
/app/local/mysql/scripts/mysql_install_db --basedir=/app/local/mysql --datadir=/app/data/mysql/data --user=mysql
# 修改 mysqld_safe 配置路径
sed -i "s#/usr/local/mysql#/app/local/mysql#g" /app/local/mysql/bin/mysqld_safe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

# 修改 my.cnf 配置文件
vi /app/local/mysql/my.cnf

#MySQL 客户端
[client]
character-set-server = utf8
port = 3306
socket = /tmp/mysql.sock


[mysql]
#prompt="(\u:HOSTNAME:)[\d]>"
#mysql 提示符中显示当前用户、数据库、时间等信息
prompt="\u@\h \R:\m:\s [\d]>"
# 取消自动补全
no-auto-rehash

#MySQL 服务端
[mysqld]
# 唯一的服务标识号,主从同步会涉及
server-id = 1
port = 3306
user = mysql
basedir = /app/local/mysql
datadir = /app/data/mysql/data
socket = /tmp/mysql.sock
log-error = /app/data/mysql/mysql_error.log
pid-file = /app/data/mysql/mysql.pid
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

# 默认存储引擎
default-storage-engine = InnoDB
# 设置最大并发连接数,如果前端程序是 PHP,可适当加大,但不可过大。如果前端程序采用连接池,可适当调小,避免连接数过大
max_connections = 512
# 最大连接错误次数,可适当加大,防止频繁连接错误后,前端 host 被 mysql 拒绝掉
max_connect_errors = 100000
# 所有线程所打开表的数量
table_open_cache = 512
# 不允许外部文件级别的锁. 打开文件锁会对性能造成负面影响
external-locking = FALSE
# 服务所能处理的请求包的最大大小以及服务所能处理的最大的请求大小
max_allowed_packet = 32M
# 启用慢查询日志
slow_query_log = 1
slow_query_log_file = /app/data/mysql/slow.log
#MySQL 打开的文件描述符限制
open_files_limit = 10240
# 操作系统在监听队列中所能保持的连接数
back_log = 600
# 每个连接都会分配的一些排序、连接等缓冲
sort_buffer_size = 16M
join_buffer_size = 16M
read_buffer_size = 16M
read_rnd_buffer_size = 16M
# 在 cache 中保留多少线程用于重用
thread_cache_size = 300
# 查询缓冲
query_cache_size = 128M
# 只有小于此设定值的结果才会被缓冲
query_cache_limit = 4M
# 设置查询缓存分配内存的最小单位
query_cache_min_res_unit = 2k
# 线程使用的堆大小
thread_stack = 512K
# 设置事务隔离级别为 READ-COMMITED,提高事务效率,通常都满足事务一致性要求
transaction_isolation = READ-COMMITTED
# 临时表的最大大小
tmp_table_size = 256M
# 独立的内存表所允许的最大容量
max_heap_table_size = 256M
# 设置慢查询阀值
long_query_time = 3
# 表示 slave 将复制事件写进自己的二进制日志
log-slave-updates
# 打开二进制日志功能
log-bin = /app/data/mysql/binlog/binlog
sync_binlog = 1
# 在一个事务中 binlog 为了记录 SQL 状态所持有的 cache 大小
binlog_cache_size = 4M
# 设置混合模式
binlog_format = MIXED
# 表示的是 binlog 能够使用的最大 cache 内存大小
max_binlog_cache_size = 8M
#binlog 最大值
max_binlog_size = 1G
# 启用中继日志
relay-log-index = /app/data/mysql/relaylog/relaylog
relay-log-info-file = /app/data/mysql/relaylog/relaylog
relay-log = /app/data/mysql/relaylog/relaylog
# 设置了只保留 7 天 binlog
expire_logs_days = 7

#MyISAM 相关选项

# 关键词缓冲的大小, 一般用来缓冲 MyISAM 表的索引块
key_buffer_size = 128M
# 排序缓存
read_rnd_buffer_size = 64M
# 限制每个进程中缓冲树的字节数
bulk_insert_buffer_size = 256M
#MyISAM 表发生变化时重新排序所需的缓冲
myisam_sort_buffer_size = 256M
#MySQL 重建索引时所允许的最大临时文件的大小
myisam_max_sort_file_size = 10G
# 如果一个表拥有超过一个索引, MyISAM 可以通过并行排序使用超过一个线程去修复他们
myisam_repair_threads = 1
# 自动检查和修复没有适当关闭的 MyISAM 表
myisam_recover

#InnoDB 相关选项

#InnoDB 存储数据字典、内部数据结构的缓冲池,16MB 已经足够大了
innodb_additional_mem_pool_size = 16M
#InnoDB 用于缓存数据、索引、锁、插入缓冲、数据字典等
# 如果是专用的 DB 服务器,且以 InnoDB 引擎为主的场景,通常可设置物理内存的 50%
# 如果是非专用 DB 服务器,可以先尝试设置成内存的 1/4,如果有问题再调整
innodb_buffer_pool_size = 4G
#InnoDB 共享表空间初始化大小,默认是 10MB,也非常坑 X,改成 1GB,并且自动扩展
innodb_data_file_path = ibdata1:1G:autoextend
# 如果将此参数设置为 1,将在每次提交事务后将日志写入磁盘,能较好保护数据可靠性。为提供性能可以设置为 0 或 2,但要承担在发生故障时丢失数据的风险
innodb_flush_log_at_trx_commit = 1
#InnoDB 的 log buffer,通常设置为 64MB 就足够了
innodb_log_buffer_size = 64M
#InnoDB redo log 大小,通常设置 256MB 就足够了
innodb_log_file_size = 256M
#InnoDB redo log 文件组,通常设置为 2 就足够了
innodb_log_files_in_group = 2
#Buffer_Pool 中 Dirty_Page 所占的数量,直接影响 InnoDB 的关闭时间
innodb_max_dirty_pages_pct = 90
# 启用 InnoDB 的独立表空间模式,便于管理
innodb_file_per_table = 1
# 控制 innodb 是否对 gap 加锁
innodb_locks_unsafe_for_binlog = 0
# 设置连接超时阀值,如果前端程序采用短连接,建议缩短这 2 个值
# 如果前端程序采用长连接,可直接注释掉这两个选项,是用默认配置(8 小时)
interactive_timeout = 120
wait_timeout = 120
# 不再进行反解析(ip 不反解成域名),这样可以加快数据库的反应时间
skip-name-resolve
# 主从复制跳过错误
slave-skip-errors = 1032,1062,126,1114,1146,1048,1396

[mysqldump]
# 不要在将内存中的整个结果写入磁盘之前缓存. 在导出非常巨大的表时需要此项
quick
max_allowed_packet = 32M
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

# 添加 mysql 到服务
vi /etc/rc.d/init.d/mysqld

#!/bin/sh
basedir=/app/local/mysql
datadir=/app/data/mysql/data
service_startup_timeout=900
lockdir='/var/lock/subsys'
lock_file_path="$lockdir/mysql"
mysqld_pid_file_path=/app/data/mysql/mysql.pid
if test -z "$basedir"
then
basedir=/usr/local/mysql
bindir=/usr/local/mysql/bin
if test -z "$datadir"
then
datadir=/usr/local/mysql/data
fi
sbindir=/usr/local/mysql/bin
libexecdir=/usr/local/mysql/bin
else
bindir="$basedir/bin"
if test -z "$datadir"
then
datadir="$basedir/data"
fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
fi
datadir_set=
lsb_functions="/lib/lsb/init-functions"
if test -f $lsb_functions ; then
. $lsb_functions
else
log_success_msg()
{
echo "SUCCESS! $@"
}
log_failure_msg()
{
echo "ERROR! $@"
}
fi

PATH="/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin"
export PATH

mode=$1 # start or stop

[ $# -ge 1 ] && shift


other_args="$*" # uncommon, but needed when called from an RPM upgrade action
# Expected: "--skip-networking --skip-grant-tables"
# They are not checked here, intentionally, as it is the resposibility
# of the "spec" file author to give correct arguments only.

case `echo "testing\c"`,`echo -n testing` in
*c*,-n*) echo_n= echo_c= ;;
*c*,*) echo_n=-n echo_c= ;;
*) echo_n= echo_c='\c' ;;
esac

parse_server_arguments() {
for arg do
case "$arg" in
--basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
bindir="$basedir/bin"
if test -z "$datadir_set"; then
datadir="$basedir/data"
fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
;;
--datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'`
datadir_set=1
;;
--pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
--service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
esac
done
}

wait_for_pid () {
verb="$1" # created | removed
pid="$2" # process ID of the program operating on the pid-file
pid_file_path="$3" # path to the PID file.

i=0
avoid_race_condition="by checking again"

while test $i -ne $service_startup_timeout ; do

case "$verb" in
'created')
# wait for a PID-file to pop into existence.
test -s "$pid_file_path" && i='' && break
;;
'removed')
# wait for this PID-file to disappear
test ! -s "$pid_file_path" && i='' && break
;;
*)
echo "wait_for_pid () usage: wait_for_pid created|removed pid pid_file_path"
exit 1
;;
esac

# if server isn't running, then pid-file will never be updated
if test -n "$pid"; then
if kill -0 "$pid" 2>/dev/null; then
: # the server still runs
else
# The server may have exited between the last pid-file check and now.
if test -n "$avoid_race_condition"; then
avoid_race_condition=""
continue # Check again.
fi

# there's nothing that will affect the file.
log_failure_msg "The server quit without updating PID file ($pid_file_path)."
return 1 # not waiting any more.
fi
fi

echo $echo_n ".$echo_c"
i=`expr $i + 1`
sleep 1

done

if test -z "$i" ; then
log_success_msg
return 0
else
log_failure_msg
return 1
fi
}

# Get arguments from the my.cnf file,
# the only group, which is read from now on is [mysqld]
if test -x ./bin/my_print_defaults
then
print_defaults="./bin/my_print_defaults"
elif test -x $bindir/my_print_defaults
then
print_defaults="$bindir/my_print_defaults"
elif test -x $bindir/mysql_print_defaults
then
print_defaults="$bindir/mysql_print_defaults"
else
# Try to find basedir in /etc/my.cnf
conf=/etc/my.cnf
print_defaults=
if test -r $conf
then
subpat='^[^=]*basedir[^=]*=\(.*\)$'
dirs=`sed -e "/$subpat/!d" -e 's//\1/' $conf`
for d in $dirs
do
d=`echo $d | sed -e 's/[ ]//g'`
if test -x "$d/bin/my_print_defaults"
then
print_defaults="$d/bin/my_print_defaults"
break
fi
if test -x "$d/bin/mysql_print_defaults"
then
print_defaults="$d/bin/mysql_print_defaults"
break
fi
done
fi

# Hope it's in the PATH ... but I doubt it
test -z "$print_defaults" && print_defaults="my_print_defaults"
fi

#
# Read defaults file from 'basedir'. If there is no defaults file there
# check if it's in the old (depricated) place (datadir) and read it from there
#

extra_args=""
if test -r "$basedir/my.cnf"
then
extra_args="-e $basedir/my.cnf"
else
if test -r "$datadir/my.cnf"
then
extra_args="-e $datadir/my.cnf"
fi
fi

parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`

#
# Set pid file if not given
#
if test -z "$mysqld_pid_file_path"
then
mysqld_pid_file_path=$datadir/`hostname`.pid
else
case "$mysqld_pid_file_path" in
/* ) ;;
* ) mysqld_pid_file_path="$datadir/$mysqld_pid_file_path" ;;
esac
fi

case "$mode" in
'start')
# Start daemon

# Safeguard (relative paths, core dumps..)
cd $basedir

echo $echo_n "Starting MySQL"
if test -x $bindir/mysqld_safe
then
# Give extra arguments to mysqld with the my.cnf file. This script
# may be overwritten at next upgrade.
$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$?

# Make lock for RedHat / SuSE
if test -w "$lockdir"
then
touch "$lock_file_path"
fi

exit $return_value
else
log_failure_msg "Couldn't find MySQL server ($bindir/mysqld_safe)"
fi
;;

'stop')
# Stop daemon. We use a signal here to avoid having to know the
# root password.

if test -s "$mysqld_pid_file_path"
then
mysqld_pid=`cat "$mysqld_pid_file_path"`

if (kill -0 $mysqld_pid 2>/dev/null)
then
echo $echo_n "Shutting down MySQL"
kill $mysqld_pid
# mysqld should remove the pid file when it exits, so wait for it.
wait_for_pid removed "$mysqld_pid" "$mysqld_pid_file_path"; return_value=$?
else
log_failure_msg "MySQL server process #$mysqld_pid is not running!"
rm "$mysqld_pid_file_path"
fi

# Delete lock for RedHat / SuSE
if test -f "$lock_file_path"
then
rm -f "$lock_file_path"
fi
exit $return_value
else
log_failure_msg "MySQL server PID file could not be found!"
fi
;;

'restart')
# Stop the service and regardless of whether it was
# running or not, start it again.
if $0 stop $other_args; then
$0 start $other_args
else
log_failure_msg "Failed to stop running server, so refusing to try to start."
exit 1
fi
;;

'reload'|'force-reload')
if test -s "$mysqld_pid_file_path" ; then
read mysqld_pid < "$mysqld_pid_file_path"
kill -HUP $mysqld_pid && log_success_msg "Reloading service MySQL"
touch "$mysqld_pid_file_path"
else
log_failure_msg "MySQL PID file could not be found!"
exit 1
fi
;;
'status')
# First, check to see if pid file exists
if test -s "$mysqld_pid_file_path" ; then
read mysqld_pid < "$mysqld_pid_file_path"
if kill -0 $mysqld_pid 2>/dev/null ; then
log_success_msg "MySQL running ($mysqld_pid)"
exit 0
else
log_failure_msg "MySQL is not running, but PID file exists"
exit 1
fi
else
# Try to find appropriate mysqld process
mysqld_pid=`pidof $libexecdir/mysqld`

# test if multiple pids exist
pid_count=`echo $mysqld_pid | wc -w`
if test $pid_count -gt 1 ; then
log_failure_msg "Multiple MySQL running but PID file could not be found ($mysqld_pid)"
exit 5
elif test -z $mysqld_pid ; then
if test -f "$lock_file_path" ; then
log_failure_msg "MySQL is not running, but lock file ($lock_file_path) exists"
exit 2
fi
log_failure_msg "MySQL is not running"
exit 3
else
log_failure_msg "MySQL is running but PID file could not be found"
exit 4
fi
fi
;;
*)
# usage
basename=`basename "$0"`
echo "Usage: $basename {start|stop|restart|reload|force-reload|status} [ MySQL server options ]"
exit 1
;;
esac

exit 0
1
2
3
4
5
6
7
8
9
10
11
12
13
# 修改权限 
chmod +x /etc/init.d/mysqld
service mysqld start

# 增加 MySQL 系统环境变量
echo 'export PATH=$PATH:/app/local/mysql/bin'>>/etc/profile && source /etc/profile

# 查看错误日志
tail -f /var/log/mysqld.log

# 用 root 账户登录并作简单的安全设置
/app/local/mysql/bin/mysql -uroot -p
直接回车空密码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 进入数据库 
use mysql;
# 设置 root 密码
UPDATE mysql.user SET Password=password('root') WHERE User='root';
# 清除 root 密码
update user set password='' where user='root';
# 删除无名用户
DELETE FROM mysql.user WHERE User='';
# 删除 root 远程访问(可选)
#DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
# 删除“test” 数据库
DROP database test;
# 允许远程访问
update user set host='%' where user='root' AND host='localhost';
# 查看所有用户权限
SELECT DISTINCT CONCAT('User:''',user,'''@''',host,''';') AS query FROM mysql.user;
# 立即生效并退出 MYSQL 命令窗体
FLUSH PRIVILEGES;QUIT;

# 创建数据库
create database ooxx;
# 创建用户
create user ooxx@'%' identified by 'ooxx';
# 对用户授权
grant all privileges on ooxx.* to ooxx;
# 刷新 MySQL 的系统权限相关表
flush privileges;
# 查看所有用户权限
SELECT DISTINCT CONCAT('User:''',user,'''@''',host,''';') AS query FROM mysql.user;

安装 Apache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cd /app/local
tar zxvf httpd-2.2.29.tar.gz
cd httpd-2.2.29

./configure --prefix=/app/local/apache \
--enable-so \
--enable-rewrite \
--enable-modes-shared=most

make && make install

vi /app/local/apache/conf/httpd.conf

# 修改主机名
ServerName localhost:80
# 查找 AddType application/x-gzip .gz .tgz, 在该行下面添加
AddType application/x-httpd-php .php
# 查找 DirectoryIndex index.html 把该行修改成
DirectoryIndex index.html index.htm index.php

/app/local/apache/bin/apachectl -t
cp /app/local/apache/bin/apachectl /etc/init.d/httpd

安装 PHP

PHP 基础环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#yum 安装或者使用下面源包编译安装
yum install libmcrypt libmcrypt-devel mcrypt mhash

# 下载地址
http://sourceforge.net/projects/mcrypt/files/Libmcrypt/
http://sourceforge.net/projects/mcrypt/files/MCrypt/
http://sourceforge.net/projects/mhash/files/mhash/

# 安装 Libmcrypt
tar -zxvf libmcrypt-2.5.8.tar.gz
cd libmcrypt-2.5.8
./configure
make && make install
cd ../

3. 安装 mhash

tar -zxvf mhash-0.9.9.9.tar.gz
cd mhash-0.9.9.9
./configure
make && make install
cd ../

4. 安装 mcrypt

tar -zxvf mcrypt-2.6.8.tar.gz
cd mcrypt-2.6.8
LD_LIBRARY_PATH=/usr/local/lib ./configure
make && make install
cd ../

### 安装 PHP

>extension 按需定制,支持 phpize 动态增加,新增的 OPcache 建议酌情开启

``` bash
tar zxvf php-5.5.27.tar.gz
cd php-5.5.27

./configure --prefix=/app/local/php \
--with-config-file-path=/app/local/php/etc \
--enable-fpm \
--enable-mbstring \
--with-mhash \
--with-mcrypt \
--with-curl \
--with-openssl \
--with-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-apxs2=/app/local/apache/bin/apxs
#--enable-opcache

make && make install

# 配置 php.ini
cp php.ini-development /app/local/php/etc/php.ini

# 设置时区
sed -i "s#;date.timezone =#date.timezone = Asia/Shanghai#g" /app/local/php/etc/php.ini
# 防止 nginx 文件类型错误解析漏洞
sed -i "s#;cgi.fix_pathinfo=1#cgi.fix_pathinfo=0#g" /app/local/php/etc/php.ini
# 禁止显示 php 版本的信息
sed -i "s#expose_php = On#expose_php = Off#g" /app/local/php/etc/php.ini
# 禁用危险函数(可选)
#sed -i "s#disable_functions =#disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source#g" /app/local/php/etc/php.ini

#enable-opcache 后设置(可选)
[OPcache]
zend_extension = opcache.so
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=1
opcache.fast_shutdown=1
opcache.enable_cli=1

配置 php-fpm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 编辑 php-fpm
cp /app/local/php/etc/php-fpm.conf.default /app/local/php/etc/php-fpm.conf
vi /app/local/php/etc/php-fpm.conf

[global]
; 错误日志
error_log = log/php-fpm.log
; 错误日志级别
log_level = notice
[www]
;php-fpm 监听端口
listen = 127.0.0.1:9000
; 启动进程的帐户和组
user = www
group = www
; 如果选择 static,则由 pm.max_children 指定固定的子进程数。如果选择 dynamic,则由后面 3 个参数动态决定
pm = dynamic
; 子进程最大数
pm.max_children = 384
; 启动时的进程数
pm.start_servers = 20
; 保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
pm.min_spare_servers = 5
; 保证空闲进程数最大值,如果空闲进程大于此值,此进行清理
pm.max_spare_servers = 35

; 设置每个子进程重生之前服务的请求数。对于可能存在内存泄漏的第三方模块来说是非常有用的。如果设置为 '0' 则一直接受请求。等同于 PHP_FCGI_MAX_REQUESTS 环境变量。默认值: 0。
pm.max_requests = 1000
; 每个子进程闲置多长时间就自杀
pm.process_idle_timeout = 10s
; 设置单个请求的超时中止时间。该选项可能会对 php.ini 设置中的 < span class="string">'max_execution_time' 因为某些特殊原因没有中止运行的脚本有用。设置为 '0' 表示 'Off'. 当经常出现 502 错误时可以尝试更改此选项。
request_terminate_timeout = 120
; 当一个请求该设置的超时时间后,就会将对应的 PHP 调用堆栈信息完整写入到慢日志中。设置为 '0' 表示 'Off'
request_slowlog_timeout = 3s
; 慢请求的记录日志, 配合 request_slowlog_timeout 使用
slowlog = /app/local/php/var/log/php-fpm.slow.log
; 设置文件打开描述符的 rlimit 限制。默认值: 系统定义值默认可打开句柄是 1024,可使用 ulimit -n 查看,ulimit -n 2048 修改。
rlimit_files = 65535
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 设置 php 环境变量
echo 'export PATH=$PATH:/app/local/php/bin'>>/etc/profile && source /etc/profile
touch /app/local/php/var/log/php-fpm.slow.log

# 添加 php-fpm 服务
cp /app/local/php-5.5.27/sapi/fpm/init.d.php-fpm /etc/rc.d/init.d/php-fpm
chmod +x /etc/rc.d/init.d/php-fpm
service php-fpm start

# 设置开机自动启动服务
vi /etc/rc.local

ulimit -SHn 65535
service php-fpm start
service nginx start
service mysqld start

配置 memcache/mongo/redis

其它 extension 扩展都可以动态添加,没事的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#memcache
cd /app/local
tar zxvf memcache-3.0.8.tgz
cd memcache-3.0.8
/app/local/php/bin/phpize
./configure --enable-memcache \
--with-php-config=/app/local/php/bin/php-config \
--with-zlib-dir
make && make install

#mongo
cd /app/local
tar zxvf mongo-1.6.10.tgz
cd mongo-1.6.10
/app/local/php/bin/phpize
./configure --with-php-config=/app/local/php/bin/php-config
make && make install

#redis
cd /app/local
tar zxvf redis-2.2.7.tgz
cd redis-2.2.7
/app/local/php/bin/phpize
./configure --with-php-config=/app/local/php/bin/php-config
make && make install

#php.ini
vi /app/local/php/etc/php.ini

[memcached]
extension=memcached.so
[mongodb]
extension=mongo.so
[redis]
extension=redis.so

# 重启生效
service php-fpm restart
php -i | grep php.ini
php -m

自动化部署

服务器的上传目录可以自定义,安装目录默认统一修改为 / app/{local,data},执行脚本为 web.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

#web.sh

#!/bin/bash

## alias
ltmp_local=$(cd "$(dirname"$0")"; pwd)
mkdir -p /app/{local,data}
unalias cp
ltmp_init=$ltmp_local/init/
ltmp_src=$ltmp_local/src/

## system

#history
cp ${ltmp_init}bashrc /etc/
#time
rm -rf /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#maildrop
sed 's/MAILTO=root/MAILTO=""/g' /etc/crontab
service crond restart
#selinux
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
#limits
echo ulimit -SHn 65535 >> /etc/profile
source /etc/profile
cp ${ltmp_init}limits.conf /etc/security/
#tcp
cp ${ltmp_init}sysctl.conf /etc/
#yum
yum -y install yum-fastestmirror
yum remove httpd mysql mysql-server php php-cli php-common php-devel php-gd -y
yum install -y wget gcc gcc-c++ openssl* curl curl-devel libxml2 libxml2-devel glibc glibc-devel glib2 glib2-devel gd gd2 gd-devel gd2-devel libaio autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel
#download

cd /app/local
##PCRE - Perl Compatible Regular Expressions
#wget"ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.37.tar.gz"
##Tengine
#wget"http://tengine.taobao.org/download/tengine-2.1.0.tar.gz"
##MySQL
#wget"https://downloads.mariadb.com/archives/mysql-5.6/mysql-5.6.25-linux-glibc2.5-x86_64.tar.gz"
##PHP
#wget"http://cn2.php.net/distributions/php-5.6.11.tar.gz"
##Mhash
#wget"http://downloads.sourceforge.net/mhash/mhash-0.9.9.9.tar.gz"
##libmcrypt
#wget"http://downloads.sourceforge.net/mcrypt/libmcrypt-2.5.8.tar.gz"
##Mcrypt
#wget"http://downloads.sourceforge.net/mcrypt/mcrypt-2.6.8.tar.gz"

## soft
cd $ltmp_local
#pcre
tar zxvf pcre-8.37.tar.gz 1> /dev/null
cd pcre-8.37
./configure
make && make install
cd ../
#tengine
groupadd www
useradd -g www www
# 安装 Tengine
cd $ltmp_local
tar zxvf tengine-2.1.0.tar.gz 1> /dev/null
cd tengine-2.1.0
./configure --user=www --group=www \
--prefix=/app/local/nginx \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre=${ltmp_local}/pcre-8.37
make && make install
cd ../
#nginx config
cd $ltmp_local
cp ${ltmp_init}nginx.conf /app/local/nginx/conf/
cp -r ${ltmp_init}vhosts /app/local/nginx/conf/
mkdir -p /app/data/localhost
chmod +w /app/data/localhost
echo "<?php phpinfo();?>" > /app/data/localhost/phpinfo.php
chown -R www:www /app/data/localhost
echo 'export PATH=$PATH:/app/local/nginx/sbin'>>/etc/profile && source /etc/profile
cp ${ltmp_init}nginx /etc/rc.d/init.d/
chmod +x /etc/init.d/nginx
ulimit -SHn 65535
service nginx start
#libmcrypt
cd $ltmp_src
tar -zxvf libmcrypt-2.5.8.tar.gz 1> /dev/null
cd libmcrypt-2.5.8
./configure
make && make install
cd ../
#mhash
cd $ltmp_src
tar -zxvf mhash-0.9.9.9.tar.gz 1> /dev/null
cd mhash-0.9.9.9
./configure
make && make install
cd ../
#mcrypt
cd $ltmp_src
tar -zxvf mcrypt-2.6.8.tar.gz 1> /dev/null
cd mcrypt-2.6.8
LD_LIBRARY_PATH=/usr/local/lib ./configure
make && make install
cd ../
#php
cd $ltmp_local
tar zxvf php-5.5.27.tar.gz 1> /dev/null
cd php-5.5.27
./configure --prefix=/app/local/php \
--with-config-file-path=/app/local/php/etc \
--enable-fpm \
--enable-mbstring \
--with-mhash \
--with-mcrypt \
--with-curl \
--with-openssl \
--with-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd
make && make install
#memcache
cd $ltmp_src
tar zxvf memcache-3.0.8.tgz 1> /dev/null
cd memcache-3.0.8
/app/local/php/bin/phpize
./configure --enable-memcache \
--with-php-config=/app/local/php/bin/php-config \
--with-zlib-dir
make && make install
#mongo
cd $ltmp_src
tar zxvf mongo-1.6.10.tgz 1> /dev/null
cd mongo-1.6.10
/app/local/php/bin/phpize
./configure --with-php-config=/app/local/php/bin/php-config
make && make install
#redis
cd $ltmp_src
#redis
tar zxvf redis-2.2.7.tgz 1> /dev/null
cd redis-2.2.7
/app/local/php/bin/phpize
./configure --with-php-config=/app/local/php/bin/php-config
make && make install
#php-fpm
cp ${ltmp_init}php.ini /app/local/php/etc/
cp ${ltmp_init}php-fpm.conf /app/local/php/etc/
echo 'export PATH=$PATH:/app/local/php/bin'>>/etc/profile && source /etc/profile
touch /app/local/php/var/log/php-fpm.slow.log
cp ${ltmp_local}/php-5.5.27/sapi/fpm/init.d.php-fpm /etc/rc.d/init.d/php-fpm
chmod +x /etc/rc.d/init.d/php-fpm
service php-fpm start

GitHub 源码仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
file://E:\QQDownload\LTMP     (2 folders, 5 files, 27.66 MB, 30.76 MB in total.)
│ httpd-2.2.29.tar.gz 7.19 MB
│ pcre-8.37.tar.gz 1.95 MB
│ php-5.5.27.tar.gz 16.95 MB
│ tengine-2.1.0.tar.gz 1.58 MB
│ web.sh 4.10 KB
├─init (1 folders, 12 files, 91.42 KB, 92.23 KB in total.)
│ │ allow.conf 35 bytes
│ │ bashrc 2.99 KB
│ │ deny.conf 35 bytes
│ │ limits.conf 1.86 KB
│ │ my.cnf 1.99 KB
│ │ mysqld 8.39 KB
│ │ nginx 2.22 KB
│ │ nginx.conf 1.34 KB
│ │ php-fpm 2.30 KB
│ │ php-fpm.conf 416 bytes
│ │ php.ini 67.83 KB
│ │ sysctl.conf 2.03 KB
│ └─vhosts (0 folders, 1 files, 826 bytes, 826 bytes in total.)
│ localhost.conf 826 bytes
└─src (0 folders, 6 files, 3.01 MB, 3.01 MB in total.)
libmcrypt-2.5.8.tar.gz 1.27 MB
mcrypt-2.6.8.tar.gz 460.85 KB
memcache-3.0.8.tgz 68.87 KB
mhash-0.9.9.9.tar.gz 909.61 KB
mongo-1.6.10.tgz 204.19 KB
redis-2.2.7.tgz 131.19 KB

LTMP - https://github.com/liaojiaxin158/LTMP

文章目录
  1. 1. 前言
  2. 2. 更新历史
  3. 3. LTMP 版本
  4. 4. 准备工作
  5. 5. 配置 Tengine
    1. 5.1. 安装 PCRE
  6. 6. 安装 Tengine
    1. 6.1. 配置 Nginx
    2. 6.2. 添加 Tengine 到服务
  7. 7. 安装 MySQL
  8. 8. 安装 Apache
  9. 9. 安装 PHP
    1. 9.1. PHP 基础环境
    2. 9.2. 配置 php-fpm
    3. 9.3. 配置 memcache/mongo/redis
  10. 10. 自动化部署
  11. 11. GitHub 源码仓库