・nginxの用途
- メールプロキシーサーバ(SMTP-Submission/SMTPS/POPS/IMAPS)
- メール認証サーバ(HTTP)
- Webサーバ(HTTPS)
・nginx のインストール
#-- 変数に必要な値を代入
DOMAIN=masdon.life
VERSION=1.17.0
IPV4=$(ip addr show eth0 | awk '/inet /{print $2}' | sed 's#/.*##')
IPV6=$(ip addr show eth0 | awk '/inet6 /&&/global/{print $2}' | sed 's#/.*##')
#-- nginx ユーザ/グループの作成と起動スクリプトを用意する為、OS標準の nginx をインストールしてアンインストール
yum install -y nginx
cp -p /usr/lib/systemd/system/nginx.service /var/tmp
yum remove -y nginx
#-- ldapに登録したメールアカウントで basic 認証ができるように nginx-auth-ldap をダウンロード
mkdir ~/work/git
git clone https://github.com/kvspb/nginx-auth-ldap.git ~/work/git/nginx-auth-ldap
#-- nginx の source のダウンロード (TLS1.3 に対応するため、source からインストールする)
cd ~/work/src
curl -L -O https://nginx.org/download/nginx-${VERSION}.tar.gz
tar xvzf nginx-${VERSION}.tar.gz && cd nginx-${VERSION}
#- build
./configure \
--prefix=/usr/local/nginx-${VERSION} \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--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_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-mail \
--with-mail_ssl_module \
--with-file-aio \
--with-cc-opt=-O2 \
--with-http_v2_module \
--add-module=../../git/nginx-auth-ldap \
--with-openssl=../openssl-1.1.1d \
--with-openssl-opt=enable-tls1_3 \
--with-stream \
--with-stream_ssl_module
make
make install
ln -s nginx-${VERSION} /usr/local/nginx
/usr/bin/cp -pf conf/* /etc/nginx/
mkdir /var/lib/nginx
chown nginx. /var/lib/nginx
#-- nginx の起動設定を修正
mv /var/tmp/nginx.service /usr/lib/systemd/system/nginx.service
sed -i -e 's#/usr/sbin/nginx#/usr/local/nginx/sbin/nginx#' \
-e '/^PIDFile/a ExecStartPre=/usr/local/bin/ipv6upchk.sh nginx' /usr/lib/systemd/system/nginx.service
・php7.3とphp-fpm のインストール
#-- remi レポジトリの追加
rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm
#-- php-fpm のインストール
yum install -y php73-php php73-php-{fpm,ldap,devel}
#-- php-fpm の設定
cp -p /etc/opt/remi/php73/php-fpm.d/www.conf{,.org}
sed -i "s/apache/nginx/" /etc/opt/remi/php73/php-fpm.d/www.conf
chown nginx /var/opt/remi/php73/log/php-fpm
chgrp nginx /var/opt/remi/php73/lib/php/*
cp -p /etc/opt/remi/php73/php.ini{,.org}
sed -i -e "s/^max_execution_time = 30/max_execution_time = 300/" \
-e "s/^max_input_time = 60/max_input_time = 300/" \
-e "s/^post_max_size = 8M/post_max_size = 20M/" \
-e "s/^upload_max_filesize = 2M/upload_max_filesize = 20M/" \
-e "s/^;date.timezone =/date.timezone = 'Asia\/Tokyo'/" /etc/opt/remi/php73/php.ini
ln -s php73 /usr/bin/php
ln -s /var/opt/remi/php73/log/php-fpm /var/log/php-fpm
#-- php を update した場合、permission が apache になるのでその対策
cat <<_EOL_>> /etc/cron.d/${DOMAIN}-cron
* * * * * root chown nginx /var/opt/remi/php73/log/php-fpm >/dev/null 2>&1
* * * * * root chgrp nginx /var/opt/remi/php73/lib/php/{opcache,session,wsdlcache} >/dev/null 2>&1
_EOL_
・nginxの設定
#-- nginx mail proxy サーバの設定
cat <<_EOL_> /etc/nginx/mail.conf
mail {
auth_http 127.0.0.1/nginx_mail_proxy/ldap_authentication.php ;
proxy on;
proxy_pass_error_message on;
include /etc/nginx/default.d/${DOMAIN}_ssl.conf;
ssl_session_cache shared:MAIL:10m;
smtp_capabilities PIPELINING 8BITMIME "SIZE 20480000";
pop3_capabilities TOP USER UIDL;
imap_capabilities IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=LOGIN;
smtp_auth login plain;
server {
listen ${IPV4}:587;
listen [${IPV6}]:587;
protocol smtp;
starttls on;
xclient on;
resolver 127.0.0.1;
auth_http_header PORT 587;
}
server {
listen ${IPV4}:465 ssl;
listen [${IPV6}]:465 ssl;
protocol smtp;
xclient on;
resolver 127.0.0.1;
auth_http_header PORT 465;
}
# server {
# listen ${IPV4}:110;
# listen [${IPV6}]:110;
# protocol pop3;
# starttls on;
# auth_http_header PORT 110;
# }
server {
listen ${IPV4}:995 ssl;
listen [${IPV6}]:995 ssl;
protocol pop3;
auth_http_header PORT 995;
}
# server {
# listen ${IPV4}:143;
# listen [${IPV6}]:143;
# protocol imap;
# starttls on;
# auth_http_header PORT 143;
# }
server {
listen ${IPV4}:993 ssl;
listen [${IPV6}]:993 ssl;
protocol imap;
auth_http_header PORT 993;
}
}
_EOL_
cp -p /etc/nginx/nginx.conf{,.org}
#-- nginx.conf の作成
cat <<'_EOL_'> /etc/nginx/nginx.conf
user nginx;
worker_processes 2;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/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"';
limit_req_zone $binary_remote_addr zone=limit_req_by_ip:10m rate=1r/m;
limit_req_log_level error;
limit_req_status 503;
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/default.d/ldap.conf;
include /etc/nginx/conf.d/*.conf;
client_max_body_size 10485760; # 10MB
}
include /etc/nginx/mail.conf;
_EOL_
#-- basic認証でldapを参照する設定
cat <<_EOL_> /etc/nginx/default.d/ldap.conf
auth_ldap_cache_enabled on;
auth_ldap_cache_expiration_time 600000;
auth_ldap_cache_size 100;
ldap_server ldap1 {
url ldap://127.0.0.1/?mailroutingaddress?sub?(objectClass=*);
satisfy any;
}
_EOL_
#-- TLSの設定
cat <<_EOL_> /etc/nginx/default.d/masdon.life_ssl.conf
ssl_protocols TLSv1.2 TLSv1.3 ;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
ssl_ecdh_curve prime256v1;
ssl_prefer_server_ciphers on;
ssl_session_timeout 5m;
ssl_certificate /etc/letsencrypt/live/masdon.life/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/masdon.life/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/masdon.life/chain.pem;
resolver 127.0.0.1 8.8.8.8 valid=300s;
resolver_timeout 10s;
_EOL_
#-- 127.0.0.1:80 は nginx mail proxy の認証で使用
#-- global は TLS証明書の更新時に使用
cat <<_EOL_> /etc/nginx/conf.d/http.conf
server {
listen 127.0.0.1:80;
server_name ${DOMAIN};
index index.html, index.php;
access_log /var/log/nginx/access_auth.log main;
error_log /var/log/nginx/error_auth.log error;
root /var/www/html/http_root;
server_tokens off;
charset utf-8;
location ~ \.php\$ {
allow 127.0.0.1;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
include fastcgi_params;
deny all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen ${IPV4}:80;
listen [${IPV6}]:80;
server_name _;
index index.html, index.php;
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log error;
root /var/www/html/http_root;
server_tokens off;
charset utf-8;
location ^~ /.well-known/acme-challenge/ {}
location ^~ /mail/ {}
location /nginx_mail_proxy/ { deny all; }
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
_EOL_
mkdir -p /var/www/html/http{,s}_root /var/log/nginx /var/cache/nginx/client_temp /etc/nginx/conf.d/https.d
cp -p /usr/local/nginx-${VERSION}/html/50x.html /var/www/html/http_root/
cp -p /usr/local/nginx-${VERSION}/html/50x.html /var/www/html/https_root/
chown -R nginx. /var/www/html/ /var/log/nginx /var/cache/nginx/client_temp
cat <<'_EOL_'> /etc/nginx/conf.d/https.conf
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name masdon.life;
include /etc/nginx/default.d/masdon.life_ssl.conf;
index index.html, index.php;
access_log /var/log/nginx/access_ssl.log main;
error_log /var/log/nginx/error_ssl.log error;
root /var/www/html/https_root;
server_tokens off;
charset utf-8;
#-- for roundcube attache file
client_max_body_size 20m;
ssl_session_cache shared:WEB:10m;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
ssl_stapling on ;
ssl_stapling_verify on ;
include /etc/nginx/conf.d/https.d/*.conf;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
}
_EOL_
・メールプロキシー認証スクリプトの作成
mkdir -p /var/www/html/http_root/nginx_mail_proxy
cat <<'_EOL_'> /var/www/html/http_root/nginx_mail_proxy/ldap_authentication.php
<?php
error_reporting(0);
// write syslog
function _writelog($message) {
openlog("nginx-mail-proxy", LOG_PID, LOG_MAIL);
syslog(LOG_INFO,"$message") ;
closelog();
}
// ldap authentication
function _ldapauth($server,$port,$dn,$passwd) {
$conn = ldap_connect($server, $port);
if ($conn) {
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);
$bind = ldap_bind($conn, $dn, $passwd);
if ($bind) {
ldap_close($conn);
return True;
} else {
ldap_close($conn);
return False;
}
} else {
return False;
}
}
function _mail_proxy($server,$port,$base,$filter,$attribute,$proxyport) {
$message = "" ;
$proxyhost = _ldapsearch($server,$port,$base,$filter,$attribute);
if ( $proxyhost === '' ) {
// proxyhost is not found
$message = "proxy=failure" ;
header('Content-type: text/html');
header('Auth-Status: Invalid login') ;
} else {
// proxyhost is found
$proxyip = gethostbyname($proxyhost);
$message = sprintf('proxy=%s:%s', $proxyhost, $proxyport );
header('Content-type: text/html');
header('Auth-Status: OK') ;
header("Auth-Server: $proxyip") ;
header("Auth-Port: $proxyport") ;
}
return $message ;
}
// ldap search
function _ldapsearch($server,$port,$base,$filter,$attribute) {
$conn = ldap_connect($server, $port);
if ($conn) {
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);
$sresult = ldap_search($conn, $base, $filter, array($attribute));
$info = ldap_get_entries($conn, $sresult);
if ( $info[0][$attribute][0] != "" ) {
return $info[0][$attribute][0];
}
}
return "" ;
}
// set $env from nginx
$env['meth'] = getenv('HTTP_AUTH_METHOD');
$env['user'] = getenv('HTTP_AUTH_USER');
$env['passwd'] = getenv('HTTP_AUTH_PASS');
$env['salt'] = getenv('HTTP_AUTH_SALT');
$env['proto'] = getenv('HTTP_AUTH_PROTOCOL');
$env['attempt'] = getenv('HTTP_AUTH_LOGIN_ATTEMPT');
$env['client'] = getenv('HTTP_CLIENT_IP');
$env['host'] = getenv('HTTP_CLIENT_HOST');
$env['port'] = getenv('HTTP_PORT');
$env['helo'] = getenv('HTTP_AUTH_SMTP_HELO');
$env['from'] = getenv('HTTP_AUTH_SMTP_FROM');
$env['to'] = getenv('HTTP_AUTH_SMTP_TO');
$log = "" ;
// protocol port map
$portmap = array(
"smtp" => 25,
"pop3" => 110,
"imap" => 143,
);
// port searvice name map
$protomap = array(
"995" => "pops",
"993" => "imaps",
"110" => "pop",
"143" => "imap",
"587" => "smtp",
"465" => "smtps",
);
// ldap setting
$ldap = array(
"host" => "127.0.0.1",
"port" => 389,
"basedn" => "",
"filter" => "(mailRoutingAddress=" . $env['user'] . ")",
"attribute" => "mailhost",
"dn" => "",
"passwd" => "",
);
// split uid and domain
$spmra = preg_split('/\@/', $env['user']) ;
// make dn
foreach (preg_split("/\./", $spmra[1]) as $value) {
$ldap['dn'] = $ldap['dn'] . 'dc=' . $value . ',' ;
}
$tmpdn = preg_split('/,$/',$ldap['dn']);
$ldap['dn'] = 'uid=' . $spmra[0] . ',ou=People,' . $tmpdn[0];
// set search attribute
if ( $env['proto'] === 'smtp' ) {
$ldap['attribute'] = 'sendmailmtahost' ;
}
// set log
$log = sprintf('meth=%s, user=%s, client=%s, proto=%s', $env['meth'], $env['user'], $env['client'], $protomap[$env['port']]);
// set password
$ldap['passwd'] = urldecode($env['passwd']) ;
// ldap authentication
if ( _ldapauth($ldap['host'],$ldap['port'],$ldap['dn'],$ldap['passwd'])) {
// authentication successful
$log = sprintf ('auth=successful, %s', $log) ;
$proxyport = $portmap[$env['proto']];
$result = _mail_proxy($ldap['host'],$ldap['port'],$ldap['basedn'],$ldap['filter'],$ldap['attribute'],$proxyport);
$log = sprintf ('%s, %s', $log,$result) ;
} else {
// authentication failure
$log = sprintf('auth=failure, %s, passwd=%s', $log, $ldap['passwd']);
// $log = sprintf('auth=failure, %s', $log);
header('Content-type: text/html');
header('Auth-Status: Invalid login') ;
}
_writelog($log);
exit;
?>
_EOL_
・nginxとphp-fpmの起動
#-- php-fpm の起動
systemctl daemon-reload
systemctl enable nginx php73-php-fpm
systemctl start nginx php73-php-fpm
#-- firewall の解放
firewall-cmd --permanent --add-port={25,587,465,993,995,443}/tcp
firewall-cmd --reload