воскресенье, 29 сентября 2013 г.

CentOS 6.2 (LAMP, nginx, memcached, percona, sendmail, dovecot, dkim-milter, iptables)

Добрый день.

Поставили передо мной задачу:
Настроить LAMP + nginx.
Создать виртуальный хост test.example.com и в index.php поместить вывод функции phpinfo.
Сделать, что бы выводился IP-адрес клиента.
Средствами nginx сделать перенаправление любых ссылок на главную страницу, настроить кеширование статики.
Установить memcached и настроить хранение php-сессий в нем.
Установить Percona server и оптимизировать настройки под характеристики сервера.
Настроить DKIM.
Все это выполнить на CentOS 6.2. Это мой первый опыт общение с RPM системами.
Вот моя небольшая заметка по этому всему.



1. Установка LAMP

1.1 Установка Apache2

# yum install httpd 

Проверим успешность установки Apache2:
# rpm -qa | grep -i httpd
httpd-tools-2.2.15-29.el6.centos.x86_64
httpd-2.2.15-29.el6.centos.x86_64

Зададим автоматическую загрузку при старте системы для сервера Apache2 с помощью chkonfig:
# chkconfig httpd on

Запустим Apache2:
# service httpd start
Starting httpd:                                            [  OK  ]


Проверим, слушает ли 80 порт Apache2:
# netstat -ap --numeric-ports | grep 80
tcp        0      0 *:80                        *:*                         LISTEN      14488/httpd 

1.2 Установка MySQL

# yum install mysql-server

Проверим успешность:
# rpm -qa | grep -i mysql-server
mysql-libs-5.5.32-1.el6.remi.x86_64
mysql-server-5.5.32-1.el6.remi.x86_64
perl-DBD-MySQL-4.013-3.el6.x86_64
mysql-5.5.32-1.el6.remi.x86_64
compat-mysql51-5.1.54-1.el6.remi.x86_64

Зададим автоматический запуск MySQL во время старта системы:
# chkconfig mysqld on

Запустим MySQL:
# service mysqld start

Теперь зададим пароль root пользователя mysql, так как если не выполнить это действие, мы можем подключиться как root без ввода пароля:
# /usr/bin/mysqladmin -u root password 'secret'

Мы зададим пароль secret для root пользователя.
Теперь проверим можем ли мы подключиться к mysql:
# mysql -uroot -psecret

И должны получить приглашение на ввод команды:
mysql >

Или же воспользуемся скриптом:
# /usr/bin/mysql_secure_installation
Во время выполнения данного скрипта (если на все вопросы ответить yes) - установит новый пароль root, удалить пользователя anonymous, запретит логиниться с удаленных машин под root-ом, удалит тестовую базу.


1.3 Установка PHP

# yum install php
Проверим установку:
# rpm -qa | grep -i php
php-cli-5.3.25-1.el6.x86_64
southbridge-php53-release-1.2-el6.southbridge.noarch
php-common-5.3.25-1.el6.x86_64
php-5.3.25-1.el6.x86_64

Установим модуль MySQL для PHP:
# yum install php-mysql

Установка дополнительных модулей (если нужно):
# yum install php-common php-mbstring php-mcrypt php-devel php-xml php-gd

Создадим файл index.php в котором будет содержаться <?php phpinfo();?> - функция для вывода информации о php:
# vi /var/www/html/index.php

Перезапустим Apache2:
# service httpd restart

1.4 Добавляем виртуальный хост:

# cd /etc/httpd/conf.d/
# mv welcome.conf welcome.conf.old
# vi test.conf
<VirtualHost *:80>
ServerName test.example.com
ServerAlias www.test.example.com
ServerAdmin webmaster@test.example.com
DocumentRoot /var/www/html
<Directory "/var/www/html">
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

Теперь если обратиться по адресу test.example.com/index.php увидим информацию о PHP на сервере.


2. Установим nginx:

# yum install nginx
# nginx -V
nginx version: nginx/1.5.3
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) 
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_perl_module --with-file-aio --with-http_image_filter_module --with-cc-opt='-O2 -g' --add-module=/root/rpmbuild/BUILD/nginx-1.5.3/nginx-upstream-fair --add-module=/root/rpmbuild/BUILD/nginx-1.5.3/ngx_cache_purge-2.0 --add-module=/root/rpmbuild/BUILD/nginx-1.5.3/nginx-upload-progress-module

Меня интересует наличие: --with-http_realip_module так, как мне нужно проксировать реальный IP-адрес клиента на Apache2.

Редактируем /etc/httpd/conf/httpd.conf Меняем Listen 80 на Listen 127.0.0.1:80 и /etc/httpd/conf.d/test.conf меняем <Virtual Host *:80> на <VirtualHost *:8080>.

Отредактируем конфигурационный файл nginx:
# vi /etc/nginx/nginx.conf

В секции server:
директиву listen 80 меняем на listen 80 default.
Так же заменим блок: 
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
на:
location / {
proxy_pass http://127.0.0.1:8080/
}

Создадим директорию для конфигурации проксирования:
# mkdir /etc/nginx/conf.d/

Создадим конфиг проксирования:
# vi /etc/nginx/conf.d/proxy.conf
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

Перезапустим Apache2 и nginx:
# service httpd restart
# service nginx restart

3. Кеширование статики через nginx:

# vi /etc/nginx/nginx.conf
Добавляем локейшен:
location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|ppt|txt|bmp|rtf|js)$ {
    root /var/www/html/;
    expires 1d;
}

Рестартанем nginx:
# service nginx restart
Теперь вставим код в /var/www/html/index.php:
# vi /var/www/html/index.php
echo "<img src=\"path to image\" />";

Обновим страницу два раза и увидим, что первый раз при скачивании картинки мы получили статус 200, при втором скачивании статус 304 Not modified. Картинка закешировалась на сутки на стороне клиента.

Во время рестарта nginx я получал такое предупреждение:
Starting nginx: nginx: [warn] the "limit_zone" directive is deprecated, use the "limit_conn_zone" directive instead in /etc/nginx/nginx.conf:37

Проблема в том, что была использована старая директива limit_zone, которая теперь заменилась на limit_conn_zone.
В конфиге nginx была строка:
limit_zone myzone $binary_remote_addr 10m;

Ее нужно заменить на:
limit_conn_zone $binary_remote_addr zone=myzone:10m;
Теперь nginx будет перезагружаться без лишний сообщений.

4. Рерайт всех запросов на index.php силами nginx:

Изменим немного location для корня сайта:
location / {
    try_files $uri /index.php;
}

И добавил location для php файлов:
location ~ \.php$ {
    proxy_pass http://127.0.0.1:8080;
}
Тут критично убрать слеш (/) в конце строки, так как на меня ругался:
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/nginx.conf:66
nginx: configuration file /etc/nginx/nginx.conf test failed


5. Хранение PHP сессий в memcache

5.1 Установка memcached

Установим memcached:
# yum install memcached

Проверим настройки, по желанию можно отредактировать:
# vi /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="512"
OPTIONS=""
Добавим memcached в автозагрузку:
# chkconfig memcached on

Запустим memcached:
# /etc/init.d/memcached start
Запускается memcached:                                     [  OK  ]

Посмотрим как работает memcached:
# echo stats | nc localhost 11211
STAT pid 17375
STAT uptime 71
STAT time 1380367858
STAT version 1.4.15
STAT libevent 1.4.13-stable
....
STAT evicted_unfetched 0
STAT evictions 0
STAT reclaimed 0
END

Теперь закроем доступ к memcached на внешний IP-так как, зачем нам доступность извне если можно подключаться только по localhost:
# iptables -A INPUT -p tcp --dport 11211 --dst 111.111.111.111 -j REJECT --reject-with tcp-reset
Теперь выполнив предыдущую команду на внешний интерфейс, мы ничего не получим:
# echo stats | nc 111.111.111.111 11211

5.2 Установка PHP расширения для memcached

Установим необходимые пакеты:
# yum install php-pear php-devel gcc zlib-devel

Установим само php расширение:
# pecl install memcache

Отредактируем php.ini:
# vi /etc/php.ini

Добавляем такие строки:
extension=memcache.so
session.save_handler = memcache
session.save_path="tcp://localhost:11211"


6. Установка и настройки Percona server 5.5

Остановим и удалим MySQL, так как он конфликтует с Percona server:
# service mysqld stop
# yum -y remove mysql-*

Установим Percona server и client:
# yum install Percona-Server-server-55 Percona-Server-client-55

Теперь запустим Percona server, имя осталось mysql, но это percona, так как у них полная совместимость:
# service mysql start
Starting MySQL (Percona Server)... SUCCESS!

Для логина используется тот же пароль, который мы задали во время установки MySQL.

Создадим необходимые функции для Percona server:
# mysql -uroot -psecret -e "CREATE FUNCTION fnv1a_64 RETURNS INTEGER SONAME 'libfnv1a_udf.so'"
# mysql -uroot -psecret -e "CREATE FUNCTION fnv_64 RETURN INTEGER SONAME 'libfnv_udf.so'"
# mysql -uroot -psecret -e "CREATE FUNCTION murmur_hash RETURN INTEGER SONAME 'libmurmur_udf.so'"
# mysql -uroot -psecret
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 5.5.33-31.1 Percona Server (GPL), Release rel31.1, Revision 566
......
mysql>
Из вывода мы видим, что тебе это Percona server.

Percona Server не создает файл конфигурации, поэтому нам надо сделать самим. Сам файл конфига можно создать с помощью Percona Configuration Wizard, где нужно ответить на несколько вопросов и в конце получить файл конфигурации. 

Теперь посмотрим, куда нам нужно поместить данный файл, что бы Percona его считал:
 # mysqld --help --verbose | head -n 30 | grep -A 1 Default

В полученном выводе найдем строчки:
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf

Что означает, что Percona пытается считать конфигурационный файл сначала из /etc/my.cnf, потом из /etc/mysql/my.cnf и так далее.
Создадим конфигурационный файл:
# vi /etc/my.cnf

В него добавим файл, который получили из Percona Configuration Wizard.
Перезагрузим:
# service mysql restart

У меня почему-то не перезагружался percona, я глянул в лог /var/lib/mysql/hostname.err, вместо hostname должен стоять hostname вашего сервера:
# tail /var/lib/mysql/hostname.err
InnoDB: Error: log file ./ib_logfile0 is of different size 0 5242880 bytes
InnoDB: than specified in the .cnf file 0 268435456 bytes!
130928 16:24:51 [ERROR] Plugin 'InnoDB' init function returned error.
130928 16:24:51 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
130928 16:24:51 [ERROR] Unknown/unsupported storage engine: InnoDB
130928 16:24:51 [ERROR] Aborting
130928 16:24:51 [Note] /usr/sbin/mysqld: Shutdown complete
130928 16:24:51 mysqld_safe mysqld from pid file /var/lib/mysql/mysql.pid ended

Видим, что проблема с движком InnoDB. Тогда я заменил его на MyISAM в:
# vi /etc/my.cnf
default-storage-engine = MyISAM

После чего все отлично заработало.

7. sendmail + Dovecot

# yum install sendmail sendmail-cf dovecot m4
Отредактируем файл /etc/mail/sendmail.mc и добавим dnl в начало этой строки:
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.01, Name=MTA')dnl
Что бы получилась строка:
dnl DAEMON_OPTIONS(`Port=smtp,Addr=127.0.01, Name=MTA')dnl

Так же добавим над строкой MAILER строку:
FEATURE(`relay_hosts_only')dnl

Выполним следующие шаги:
# hostname >> /etc/mail/relay-domains

Скомпилируем конфиг для sendmail:
# m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf

Отредактируем конфигурационный файл dovecot:
# vi /etc/dovecot/dovecot.conf
protocol = imap
listen = *, ::
mail_location = mbox:~/mail:INBOX=/var/mail/%u

Автоматический запуск сервисов со стартом системы:
# chkconfig dovecot on
# chkconfig sendmail on

Перезапустим сервисы:
# service dovecot restart
# service sendmail restart


8. Настроим DKIM + sendmail

Установим утилиту для подписи dkim-milter:
# yum install dkim-milter

Создадим каталог для будущих ключей для подписи:
# mkdir /etc/mail/dkim-milter/keys/example.com
# cd /etc/mail/dkim-milter/keys/example.com

Сгенерируем открытый (2013.txt) и приватный (2013.private) ключи:
# dkim-genkey -s 2013 -d example.com

Добавить в DNS запись из 2013.txt и _adsp._domainkey.example.com. IN TXT "dkim=all"

Поменяем владельца для созданного каталога:
# chown -R dkim-milter:dkim-milter /etc/mail/dkim-milter/keys/example.com

И переименуем приватный ключ:
# mv /etc/mail/dkim-milter/keys/example.com/2013.private /etc/mail/dkim-milter/keys/example.com/2013

Отредактируем несколько полей в конфигурационном файле dkim-milter:
# vi /etc/mail/dkim-milter/dkim-filter.conf
Domain example.com
KeyList /etc/mail/dkim-milter/dkim-keys.conf
Selector 2013
Socket  local:/var/run/dkim-milter/dkim-milter.sock
UserID dkim-milter

Создадим файл, где укажем для какихе пользователей подписывать письма, в моем случае для всех:
# vi /etc/mail/dkim-milter/dkim-keys.conf
*:example.com:/etc/mail/dkim-milter/keys/example.com/2013

Запуск dkim-milter во время старта системы:
# chkconfig dkim-milter on

Запустим сервис:
# service dkim-milter start

Теперь отредактируем конфигурационный файл sendmail:
# vi /etc/sendmail.mc
Добавим такую запись в самом конце:
INPUT_MAIL_FILTER(`dkim-filter', `S=local:/var/run/dkim-milter/dkim-milter.sock')
Скомпилируем и перезапустим сервис (второй вариант, без m4):
# make
# make restart

Теперь можно проверить работоспособность:
# echo 'test' | mutt -e 'set from='noreply@example.com'' -e 'set realname='User'' -e 'set smtp_url='smtp://localhost:25'' -s 'DKIM' you@email.com

И посмотрим исходники письма:

Видим подпись, все хорошо!

Полезные ссылки:

Комментариев нет:

Отправить комментарий