# cd /opt/src/ && wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.5.tar.gz http://maloletka.ru/patches/rpaf-0.5.patch # tar xvf mod_rpaf-0.5.tar.gz # cd mod_rpaf-0.5 && cat ../rpaf-0.5.patch | patch -p0 mod_rpaf-2.0.c # less README и ставим модуль
nginx:user nobody nogroup;
worker_processes 4;
error_log /var/log/nginx/error_log info;
events {
worker_connections 8192;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;
gzip off;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
index index.html;
server {
listen 80;
server_name domain.com www.domain;
root /home/clients/vasiliy_pupkinson/domains/domain.com/html;
location / {
proxy_pass http://127.0.0.1:8080/;
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;
proxy_max_temp_file_size 0;
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;
}
location ~* ^.+.(jpg|gif|png|avi|mpg|zip|exe)$ {
root /home/clients/vasiliy_pupkinson/domains/domain.com/html;
valid_referers none blocked server_names;
if ($invalid_referer) {
return 403;
}
}
}
}
apache:LoadModule rpaf_module libexec/mod_rpaf.so
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 APACHE_IPS
Listen 127.0.0.1:8080
ServerName localhost
NameVirtualHost 127.0.0.1:8080
<VirtualHost 127.0.0.1:8080>
ServerName domain.com
ServerAlias domain.com
ServerAlias www.domain.com
DocumentRoot /home/clients/vasiliy_pupkin/domains/domain.com/html
CustomLog /home/clients/vasiliy_pupkin/domains/domain.com/logs/access_log combined
ErrorLog /home/clients/vasiliy_pupkin/domains/domain.com/logs/error_log
ScriptAlias /cgi-bin/ " /home/clients/vasiliy_pupkin/domains/domain.com/html/cgi-bin/ "
<Directory "/cgi-bin/">
Options None +FollowSymLinks
</Directory>
<Directory />
Options All -Indexes
AllowOverride All
</Directory>
</VirtualHost>
В итоге имеем:
nginx на 80 порту ловит все входящие соединения и отдает юзеру все файлы, что попадают под регексп. Я туда еще добавил хотлинк-протект для пущего гламуру.
В регексп успешно можно пихать html, css и т.п.
Все, что не попадает под паттерн, передается apache, который слушает на 127.0.0.1:8080.
Без модуля mod_rpaf апач в логи будет писать src ip 127.0.0.1, так что ставим его обязательно.
Основной недостаток - это необходимость переписывать правила из .htaccess под nginx, что, в принципе, не очень сложно.
А простой redirect и так должен работать.
Стадию разметки пропускаю по причине различных конфигураций для каждого отдельно взятого сетапа.
mount -t ext3 /dev/sda1 /mnt
debootstrap etch /mnt http://ftp.debian.org/debian/
proc и чрутимся:mount -t proc proc /mnt/proc chroot /mnt
# cat > /etc/apt/apt.conf APT::Default-Release "stable"; APT::Force-LoopBreak "true";
# cat > /etc/apt/sources.list deb http://ftp.debian.org/debian etch main non-free contrib deb http://security.debian.org/ etch/updates main contrib non-free deb http://ftp.debian.org/debian etch-proposed-updates main non-free contrib
# cat > /etc/resolv.conf nameserver YOUR_NAMESERVER1_IP nameserver YOUR_NAMESERVER2_IP
# cat > /etc/fstab /dev/sda1 / ext3 defaults 0 1 /dev/sda2 none swap sw 0 0 /dev/sda3 /home ext3 defaults,errors=remount-ro,noatime,nodiratime 0 0 proc /proc proc defaults 0 0
# cat > /etc/hosts 127.0.0.1 localhost serverlabel.YOUR_DOMAIN.COM
# cat > /etc/hostname serverlabel.YOUR_DOMAIN.COM
# cat >> /etc/bash.bashrc if [ -f /etc/bash_completion ]; then . /etc/bash_completion fi
# cat > /etc/network/interfaces auto lo iface lo inet loopback auto eth0 iface eth0 inet static address СИСТЕМНЫЙ IP netmask 255.255.255.0 network СЕТЬ broadcast СЕТЬ.255 gateway ШЛЮЗ dns-nameservers YOUR_NAMESERVER1_IP YOUR_NAMESERVER2_IP
# cat > /etc/locale.gen en_GB ISO-8859-1 en_US ISO-8859-1 ru_RU.KOI8-R KOI8-R
# ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime # cat > /etc/timezone Etc/UTC
# /usr/bin/apt-get update # /usr/bin/apt-get dist-upgrade # /usr/bin/apt-get -y -q install ssh alien aria2 arping bash bash-completion bc bridge-utils build-essential busybox bzip2 bzr checkinstall chkconfig chkrootkit coreutils cpio cron curl cvs dash debian-archive-keyring debian-keyring diffutils dmidecode dnsutils dos2unix dosfstools dselect e2fsprogs ebtables ethtool ext3grep extundelete fakeroot findutils fping fuse gcc gdb geoip-bin geoip-database git gzip hdparm hostname htop iotop ipcalc iperf ipmitool iproute iptables iputils-ping less lftp libc6-dev libwww-perl links lm-sensors locales logrotate lrzip lsb-security lsof lvm2 lzma make mdadm mercurial monit mtr mysqltuner mytop nano netcat nmap ntfs-3g ntp openipmi p7zip p7zip-full parallel parted patch pbzip2 pciutils perl pigz procps psmisc pwgen python rkhunter rsync rsyslog ruby screen sed snmp sqlite3 strace subversion sysstat tar tcpdump tcsh telnet tmux unhide unzip usbutils uw-mailutils vim wget whois xinetd xz-utils zip # /usr/sbin/ntpdate pool.ntp.org # echo "0 0 * * * /usr/sbin/ntpdate pool.ntp.org >/dev/null 2>&1" | /usr/bin/crontab - # cd /dev && MAKEDEV generic # source /etc/bash.bashrc
grub:# cp -a /usr/lib/grub/i386-pc /boot/grub
/usr/src:# cd /usr/src/linux
# make-kpkg --bzImage kernel_image # dpkg -i /usr/src/linux-image-x.x.x-blablabla.deb
grub в mbr:# update-grub # grub --no-floppy > root (hd0,0) > setup (hd0) > quit
MyConfig.cgi.sh со следующим содержимым:#!/bin/sh CFLAGS="-O2" ./configure --prefix=/opt/php-x.x.x-fcgi \ --enable-calendar \ --enable-sysvsem \ --enable-sysvshm \ --enable-sysvmsg \ --enable-ftp \ --with-mcrypt \ --with-mysql \ --with-mysqli \ --enable-bcmath \ --with-bz2 \ --with-gd \ --with-jpeg-dir \ --with-zlib-dir \ --with-curl \ --enable-sockets \ --with-iconv \ --enable-mbstring \ --enable-mbregex \ --enable-ctype \ --enable-shmop \ --enable-wddx \ --with-imap \ --with-freetype-dir \ --with-xmlrpc \ --enable-dbase \ --with-mime-magic \ --with-mhash \ --with-gettext \ --with-imap-ssl \ --with-pear \ --with-kerberos \ --with-openssl \ --with-snmp \ --with-config-file-path=/opt/etc/phpX \ --enable-fastcgi \ --enable-force-cgi-redirect \ --enable-fpm
# sh MyConfig.cgi.sh # make # make install
fcgi.sh со следующим содержимым:
#!/bin/bash
# ABSOLUTE path to the PHP binary
PHPFCGI="/opt/php-x.x.x-fcgi/bin/php-cgi"
# tcp-port to bind on
FCGIPORT="8888"
# IP to bind on
FCGIADDR="127.0.0.1"
# number of PHP children to spawn
PHP_FCGI_CHILDREN=5
# number of request before php-process will be restarted
PHP_FCGI_MAX_REQUESTS=1000
# allowed environment variables sperated by spaces
ALLOWED_ENV="PATH USER"
# if this script is run as root switch to the following user
USERID=www-data
################## no config below this line
if test x$PHP_FCGI_CHILDREN = x; then
PHP_FCGI_CHILDREN=5
fi
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_CHILDREN"
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS"
ALLOWED_ENV="$ALLOWED_ENV FCGI_WEB_SERVER_ADDRS"
if test x$UID = x0; then
EX="/bin/su -m -c \"$PHPFCGI -q -b $FCGIADDR:$FCGIPORT\" $USERID"
else
EX="$PHPFCGI -b $FCGIADDR:$FCGIPORT"
fi
echo $EX
# copy the allowed environment variables
E=
for i in $ALLOWED_ENV; do
E="$E $i=${!i}"
done
# clean environment and set up a new one
nohup env - $E sh -c "$EX" &> /dev/null &
nginx будет выглядеть таким образом:server {
listen 1.2.3.4:80;
server_name domain.com www.domain.com;
access_log /dev/null;
# max POST size in bytes
client_max_body_size 1000000000;
location / {
root /home/clients/ftp_login/domains/domain.com/html;
index index.html index.htm index.php;
}
location ~ \.php$ {
# Commented block - for accelerated POST - nginx should be 0.5.9+
# fastcgi_pass_request_body off;
# client_body_in_file_only clean;
# fastcgi_param REQUEST_BODY_FILE $request_body_file;
fastcgi_pass 127.0.0.1:8888;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/clients/ftp_login/domains/domain.com/html$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param REDIRECT_STATUS 200;
}
# hotlink protection
location ~* ^.+\.(gif|jpg|mpg|mp3|mpeg|avi)$ {
valid_referers none blocked domain.com www.domain.com;
if ($invalid_referer) {
return 403;
}
}
}
/usr/src, распаковываем, заходим в директорию и стартуем ./runme set. /usr/src/linux, а iptables - в /usr/src/iptables. /usr/src/linux и делаем make oldconfig, где указываем поддержку фич ipset модулями.Собираем и устанавливаем ядро:
# make-kpkg --bzImage kernel_image # dpkg -i /usr/src/linux-image-x.x.x-blablabla.deb
# apt-get install ipset
ipset в /etc/modules и либо загружаем модуль modprobe ipset, либо перезагружаемся в новое ядро.iptables. Стоит учесть, что максимальное количество ip в списке - 65536 штук:# ipset -N blacklist iphash
#!/usr/bin/perl
while ($line = <STDIN>) {
if ($line =~ /^\s+(\d+) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
print $2, ".", $3, ".", $4, ".", $5, "\n" if ($1 > $ARGV[0]);
}
}
cron:
#!/bin/bash
# variables, change them to get script work
BADREQUEST="GET / HTTP/1.1";
LOGPATH="/home/clients/login_ftp0/domains/domain.com/logs/access_log";
MINREQUESTS="50";
SCRIPTHOME="/root/antiddos";
# don't change anything bellow
grep "${BADREQUEST}" $LOGPATH | awk -F ' ' '{ print $ 1 }' | sort | uniq -c | ${SCRIPTHOME}/num-filter.pl $MINREQUESTS >> ${SCRIPTHOME}/in_blacklist.add.pre
sort -u < ${SCRIPTHOME}/in_blacklist.add.pre > ${SCRIPTHOME}/in_blacklist.add
cat ${SCRIPTHOME}/in_blacklist.add > ${SCRIPTHOME}/in_blacklist
for i in `cat ${SCRIPTHOME}/in_blacklist`;
do
/usr/sbin/ipset -q -A blacklist $i;
done
iptables:/sbin/iptables -F /sbin/iptables -X DDOS_HTTP_FILTER /sbin/iptables -N DDOS_HTTP_FILTER /sbin/iptables -A DDOS_HTTP_FILTER -d $IP -p tcp --syn --dport 80 -m set --set blacklist src -j DROP /sbin/iptables -A DDOS_HTTP_FILTER -d $IP -p tcp --syn --dport 80 -m hashlimit --hashlimit 10/min --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-name DDOS --hashlimit-htable-size 32768 --hashlimit-htable-max 32768 --hashlimit-htable-gcinterval 1000 --hashlimit-htable-expire 100000 -j ACCEPT /sbin/iptables -A DDOS_HTTP_FILTER -d $IP -p tcp --dport 80 --syn -j DROP /sbin/iptables -A DDOS_HTTP_FILTER -d $IP -p tcp --syn --dport 80 -m connlimit --connlimit-above 10 -j DROP /sbin/iptables -A DDOS_HTTP_FILTER -j ACCEPT /sbin/iptables -A INPUT -p tcp --dport http -j DDOS_HTTP_FILTER
Фильтрация с GeoIP
# apt-get install xtables-addons-source #
#!/bin/bash
iptables=/usr/local/sbin/iptables
ipset=/usr/sbin/ipset
WHITE="195.88.52.82/32"
ddos_enable() {
# whitelist
$iptables -N WHITELIST
for i in $WHITE;
do
$iptables -A WHITELIST -s $i -j ACCEPT;
done
$iptables -A WHITELIST -j DROP
$iptables -N DDOS_HTTP_FILTER
$iptables -A DDOS_HTTP_FILTER -m hashlimit --hashlimit 15/min --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-name HTTPDDOS --hashlimit-htable-size 32768 --hashlimit-htable-max 32768 --hashlimit-htable-gcinterval 1000 --hashlimit-htable-expire 100000 -j ACCEPT
$iptables -A DDOS_HTTP_FILTER -m connlimit --connlimit-above 15 -j DROP
$iptables -A DDOS_HTTP_FILTER -j ACCEPT
$iptables -N SORT_FILTER
$iptables -A SORT_FILTER -p tcp --dport 80 --syn -j DDOS_HTTP_FILTER
$iptables -A SORT_FILTER -p tcp -m multiport --dports 25,53 -j ACCEPT
$iptables -A SORT_FILTER -p udp --dport 53 -j ACCEPT
$iptables -A SORT_FILTER -j WHITELIST
$iptables -N GEOIP_FILTER
$iptables -A GEOIP_FILTER -m geoip --src-cc AM,AZ,BY -j SORT_FILTER
$iptables -A GEOIP_FILTER -m geoip --src-cc EE,GE,KZ -j SORT_FILTER
$iptables -A GEOIP_FILTER -m geoip --src-cc LV,MD,NL,RU -j SORT_FILTER
$iptables -A GEOIP_FILTER -m geoip --src-cc UA,UZ,US -j SORT_FILTER
$iptables -A GEOIP_FILTER -j DROP
$iptables -I INPUT 1 -i lo -j ACCEPT
$iptables -I INPUT 2 -m set --set blacklist src -j DROP
$iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$iptables -A INPUT -j GEOIP_FILTER
}
start_iptables() {
# whitelist
$iptables -N WHITELIST
for i in $WHITE;
do
$iptables -A WHITELIST -s $i -j ACCEPT;
done
$iptables -A WHITELIST -j DROP
# default rules
$iptables -I INPUT 1 -i lo -j ACCEPT
$iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$iptables -A INPUT -p tcp -m multiport --dports 25,53,80 -j ACCEPT
$iptables -A INPUT -p udp --dport 53 -j ACCEPT
$iptables -A INPUT -j WHITELIST
}
clear_iptables() {
$iptables -F
$iptables -X
}
start_ipset() {
$ipset -q -N blacklist iphash
}
clear_ipset() {
$ipset -q -F blacklist
$ipset -q -X blacklist
}
case "$1" in
normal)
clear_iptables
start_iptables
echo "normal mode activated"
;;
stop)
clear_iptables
clear_ipset
echo "iptabes cleared"
;;
hard)
clear_iptables
start_ipset
ddos_enable
echo "hard mode activated"
;;
*)
echo "Usage $0 {normal|hard|stop}"
exit 1
;;
esac
#!/usr/bin/env bash PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:~/bin SCRIPTHOME="/root/antiddos" function valid_ip() { local ip=$1 local stat=1 [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] && { OIFS=$IFS IFS='.' ip=($ip) IFS=$OIFS [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] stat=$? return $stat } } ############### [[ -d $SCRIPTHOME ]] || exit 1 if ! VALID_IP=$(valid_ip "$1") then echo "Usage: $0 <IP ADDR>" >&2 exit 1 fi sed_cmd="/$1/d;/^[[:space:]]*$/d;s/[[:space:]]*$//" if LISTS=$(grep -lIrx "$1" "$SCRIPTHOME" | grep -v "\.sh") then for i in $LISTS do echo "Removing $1 from $i" sed -i '' "$sed_cmd" ${i} done nginx -t && nginx -s reload fi