Bitacora de configuración de un servidor web y email en un VPS de OVH. Como servidor web: nginx y como servidor de email: postfix con un servidor ubuntu 14.04.
KERNEL
/etc/sysctl.conf
# Avoid a smurf attack
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Turn on protection for bad icmp error messages
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Turn on syncookies for SYN flood attack protection
net.ipv4.tcp_syncookies = 1
# Turn on and log spoofed, source routed, and redirect packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# No source routed packets here
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Turn on reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Make sure no one can alter the routing tables
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# Don't act as a router
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
REDIMENSIONADO PARTICION
- resize2fs /dev/sda1 50G
- fdisk -l /dev/sda -> ver donde se inicia la particion (bloque 4096)
- fdisk /dev/sda -> d 1 -> borrar la particion 1
-> n, p, 1 -> crear particion nueva primaria la nº 1
-> el primer sector que sea igual que la original (4096) y de un tamaño ligeramente superior a lo que hemos puesto en el resize2fs
-> w -> escribir cambios
- resize2fs /dev/sda1
MYSQL
Este post se explica
Al finalizar ejecutar: mysql-secure-installation
NGINX
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
##keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Buffer overflow
##
client_body_buffer_size 128K;
#client_header_buffer_size 4 256K;
#client_max_body_size 1K;
large_client_header_buffers 4 256K;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
##
# Limits
##
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=50r/s;
limit_conn conn_limit_per_ip 20;
limit_req zone=req_limit_per_ip burst=20;
server {
listen ip:80;
server_name "";
return 444;
}
server {
listen ip:80 default_server;
server_name _;
return 444;
}
site1.conf:
server {
listen ip:80;
server_name site1.com www.site1.com;
root /home/www/test1;
index index.html index.htm index.php;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
# errores los redirigimos
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /home/www/error;
}
location = /404.html {
root /home/www/error;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
try_files $uri = 404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\. {
deny all;
}
# en los directiorios de upload no damos php. OJO REVISAR LOS DIRECTIORIOS!!
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
FIREWALL
PHPMYADMIN
Protejer directorio:
crear en el archivo de configuración del site de nginx:
location /sqladmin {
allow 127.0.0.1;
allow ip;
deny all;
auth_basic "Login";
auth_basic_user_file /etc/nginx/pass_sql;
}
No dejamos el acceso a root a phpmyadmin:
editar /etc/phpmyadmin/config.inc.php y buscar la linea:
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
añadir:
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['AllowRoot'] = FALSE;
FAIL2BAN
Para detener ataques de fuerza bruta usamos fail2ban contra el acceso SSH y el acceso a /sqladmin del SITE
- editamos el /etc/fail2ban/jail.conf
-> ponemos mail de destino
-> ponemos en ignoreip las ip que queremos que salten el filtro
-> action = %(action_mwl)s
- comentamos los servicios que no queremos monitorizar dejando:
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
POSTFIX
Nos interesa recibir mails dirigidos a nuestos dominios (@site1, @site2, etc) y que estos sean reenviados a cuentas nuestras, es decir a gmail. P.e: un mail a comercial@site1.com -> mi sevidor postfix -> micuenta@gmail.com
biff = no
append_dot_mydomain = no
readme_directory = no
smtpd_relay_restrictions = permit_mynetworks reject_unauth_destination
myhostname = vpsXXXXX.ovh.net
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
#myorigin = site1.com
mydestination = vpsXXXXX.ovh.net, localhost.ovh.net, , localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4
disable_vrfy_command = yes
initial_destination_concurrency = 2
default_destination_concurrency_limit = 5
home_mailbox=Maildir/
#anti dos
default_process_limit = 100
smtpd_client_connection_count_limit = 10
smtpd_client_connection_rate_limit = 30
header_size_limit = 51200
message_size_limit = 10485760
smtpd_recipient_limit = 100
#redireccion de los @sites
virtual_alias_domains = site1.com site2.com
virtual_alias_maps = hash:/etc/postfix/virtual
contact@site1.com micuenta@gmail.com
contact@site2.com micuenta@gmail.com
@localhost root
@ root
@vpsXXXXXX.net root
De manera que si recibo un mail dirigido a contact@site1.com o site2.com lo envia a la cuenta de gmail. Cualquier otra cosa que se envie a los "mydestination" se envia al usuario local root.
OJO! gmail te puede tachar de spammer por lo que los registros de DNS i SPF deben estar bien configurados. Por lo que se puede hacer es redirigir los emails a una cuenta local del servidor + instalar un servidor pop3 para que mi cuenta de gmail se descarge los emails del servidor.
DOVECOT
apt-get install dovecot-pop3d
/etc/dovecot/conf.d/10-auth.conf -> disable_plaintext_auth = no
/etc/dovecot/conf.d/10-master.conf -> inet_listener pop3s { port = 0 }
/etc/dovecot/conf.d/10-mail.conf -> mail_location = maildir:~/Maildir
Asi dejamos acceder al servidor por pop3 sin seguridad.
Configuramos postfix via /etc/postfix/virtual que entregue los correos a un usuario local sin permisos y sin capacidad de hacer login (/bin/false como shell). Configuramos la cuenta de google para que recupere por pop3 los mails de nuestro servidor de ese usuario.
Modificamos el script de firewall:
GOOGLE="64.18.0.0/20 64.233.160.0/19 66.102.0.0/20 66.249.80.0/20 72.14.192.0/18 74.125.0.0/16 173.194.0.0/16 207.126.144.0/20 209.85.128.0/17 216.58.208.0/20 216.239.32.0/19"
for ipgoogle in $GOOGLE
do
$ipt -A INPUT -i $EXTIF -s $ipgoogle -d $EXTIP -p tcp --dport 110 -j ACCEPT
done
Así solo dejamos acceder al pop3 desde los servidores de google.
KERNEL
/etc/sysctl.conf
# Avoid a smurf attack
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Turn on protection for bad icmp error messages
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Turn on syncookies for SYN flood attack protection
net.ipv4.tcp_syncookies = 1
# Turn on and log spoofed, source routed, and redirect packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# No source routed packets here
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Turn on reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Make sure no one can alter the routing tables
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# Don't act as a router
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
REDIMENSIONADO PARTICION
- arrancar en modo rescate desde la consola de gestión de OVH.
- Reducir partición para crear una partición sin permisos de execución para dotar de mas seguridad al webserver / mysql
- resize2fs /dev/sda1 50G
- fdisk -l /dev/sda -> ver donde se inicia la particion (bloque 4096)
- fdisk /dev/sda -> d 1 -> borrar la particion 1
-> n, p, 1 -> crear particion nueva primaria la nº 1
-> el primer sector que sea igual que la original (4096) y de un tamaño ligeramente superior a lo que hemos puesto en el resize2fs
-> w -> escribir cambios
- resize2fs /dev/sda1
- Crear particion nueva en el hueco que hemos generado para tener nuestra nueva particion para datos. Crear el sistema de archivos: mkfs.ext4 /dev/sda3
- Montar / y Modificar el fstab para que la monte con opciones de seguridad (rw,auto,nouser,nodev,noexec,nosuid,async (defaults pero con noexec)).
- Reiniciar
MYSQL
Este post se explica
Al finalizar ejecutar: mysql-secure-installation
NGINX
- apt-get install ngingx php5-fpm php-pear php5-mysql
- /etc/php5/fpm/php.ini -> poner cgi.fix_pathinfo = 0
- /etc/php5/fpm/pool.d/www.conf -> listen = /var/run/php5-fpm.sock -> para conectar con php por socket y no por TCP.
- Protección a /etc/ngingx/nginx.conf
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
##keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Buffer overflow
##
client_body_buffer_size 128K;
#client_header_buffer_size 4 256K;
#client_max_body_size 1K;
large_client_header_buffers 4 256K;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
##
# Limits
##
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=50r/s;
limit_conn conn_limit_per_ip 20;
limit_req zone=req_limit_per_ip burst=20;
- Creamos los sitios web en /etc/nginx/sites-available y crear el correspondiente link en /etc/nginx/sites-enabled
server {
listen ip:80;
server_name "";
return 444;
}
server {
listen ip:80 default_server;
server_name _;
return 444;
}
site1.conf:
server {
listen ip:80;
server_name site1.com www.site1.com;
root /home/www/test1;
index index.html index.htm index.php;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
# errores los redirigimos
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /home/www/error;
}
location = /404.html {
root /home/www/error;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
try_files $uri = 404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\. {
deny all;
}
# en los directiorios de upload no damos php. OJO REVISAR LOS DIRECTIORIOS!!
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
FIREWALL
#!/bin/bash ################# # FIREWALL script ################# ipt=/sbin/iptables EXTIP="ip" EXTIF="eth0" LOIF="lo" # Se bloquea todo $ipt -P INPUT DROP $ipt -P FORWARD DROP $ipt -P OUTPUT ACCEPT $ipt -F $ipt -X bad_packets $ipt -X broadcasts # conexiones locales si $ipt -A INPUT -i $LOIF -j ACCEPT $ipt -A OUTPUT -o $LOIF -j ACCEPT # creamos chain para paquetes malformados $ipt -N bad_packets $ipt -N broad$ipt -A bad_packets -p tcp ! --syn -m state --state NEW -j DROP $ipt -A bad_packets -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP $ipt -A bad_packets -p tcp --tcp-flags ALL ALL -j DROP $ipt -A bad_packets -p tcp --tcp-flags ALL NONE -j DROP $ipt -A bad_packets -p tcp --tcp-flags SYN,RST SYN,RST -j DROP $ipt -A bad_packets -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP $ipt -A bad_packets -p tcp --tcp-flags FIN,ACK FIN -j DROP $ipt -A bad_packets -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP #byebye broadcasts, multicasts $ipt -A broadcasts -m pkttype --pkt-type broadcast -j DROP $ipt -A broadcasts -m pkttype --pkt-type multicast -j DROP $ipt -A broadcasts -m state --state INVALID -j DROP ##################################### # INPUT #################################### # si los paquetes son ok permitimos las conexiones establecidas i pings $ipt -A INPUT -i $EXTIF -j bad_packets $ipt -A INPUT -i $EXTIF -j broadcasts $ipt -A INPUT -i $EXTIF -m state --state ESTABLISHED,RELATED -j ACCEPT $ipt -A INPUT -i $EXTIF -p icmp --icmp-type 8 -j ACCEPT # Dejamos acceder por ssh i HTTP $ipt -A INPUT -i $EXTIF -d $EXTIP -p tcp --dport 22 -j ACCEPT $ipt -A INPUT -i $EXTIF -d $EXTIP -p tcp --dport 80 -j ACCEPT ##################################### # OUTPUT ##################################### #el usuario www-data no puede salir a internete $ipt -A OUTPUT -o $EXTIF -m owner --uid-owner www-data -m multiport -p tcp --dports 80,21,23,22,443,445,8080,81 -j DROP $ipt -A OUTPUT -o $EXTIF -m state --state ESTABLISHED,RELATED -j ACCEPT #$ipt -A OUTPUT -o $EXTIF -p icmp --icmp-type 0 -j ACCEPT #$ipt -A OUTPUT -o $EXTIF -p tcp --sport 22 -j ACCEPT #$ipt -A OUTPUT -o $EXTIF -p tcp --sport 80 -j ACCEPT
PHPMYADMIN
- apt-get install phpmyadmin mcrypt -> responder a las preguntas que si
- php5enmod mcrypt
- restart php5-fpm
- ln -s /usr/share/phpmyadmin /.../html
- mv /.../html/phpmyadmin /.../html/sqladmin
Protejer directorio:
- apt-get install apache2-utils
- httpasswd -c /etc/nginx/pass
--> introducir password - chmod 640 /etc/nginx/pass
- chown root.www-data /etc/nginx/pass
crear en el archivo de configuración del site de nginx:
location /sqladmin {
allow 127.0.0.1;
allow ip;
deny all;
auth_basic "Login";
auth_basic_user_file /etc/nginx/pass_sql;
}
No dejamos el acceso a root a phpmyadmin:
editar /etc/phpmyadmin/config.inc.php y buscar la linea:
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
añadir:
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['AllowRoot'] = FALSE;
FAIL2BAN
Para detener ataques de fuerza bruta usamos fail2ban contra el acceso SSH y el acceso a /sqladmin del SITE
- editamos el /etc/fail2ban/jail.conf
-> ponemos mail de destino
-> ponemos en ignoreip las ip que queremos que salten el filtro
-> action = %(action_mwl)s
- comentamos los servicios que no queremos monitorizar dejando:
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
POSTFIX
Nos interesa recibir mails dirigidos a nuestos dominios (@site1, @site2, etc) y que estos sean reenviados a cuentas nuestras, es decir a gmail. P.e: un mail a comercial@site1.com -> mi sevidor postfix -> micuenta@gmail.com
- apt-get install postfix -> aplicamos configuracion de Internet Site
- modificamos /etc/postfix/main.cf:
biff = no
append_dot_mydomain = no
readme_directory = no
smtpd_relay_restrictions = permit_mynetworks reject_unauth_destination
myhostname = vpsXXXXX.ovh.net
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
#myorigin = site1.com
mydestination = vpsXXXXX.ovh.net, localhost.ovh.net, , localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4
disable_vrfy_command = yes
initial_destination_concurrency = 2
default_destination_concurrency_limit = 5
home_mailbox=Maildir/
#anti dos
default_process_limit = 100
smtpd_client_connection_count_limit = 10
smtpd_client_connection_rate_limit = 30
header_size_limit = 51200
message_size_limit = 10485760
smtpd_recipient_limit = 100
#redireccion de los @sites
virtual_alias_domains = site1.com site2.com
virtual_alias_maps = hash:/etc/postfix/virtual
- en /etc/postfix/virtual:
contact@site1.com micuenta@gmail.com
contact@site2.com micuenta@gmail.com
@localhost root
@ root
@vpsXXXXXX.net root
De manera que si recibo un mail dirigido a contact@site1.com o site2.com lo envia a la cuenta de gmail. Cualquier otra cosa que se envie a los "mydestination" se envia al usuario local root.
OJO! gmail te puede tachar de spammer por lo que los registros de DNS i SPF deben estar bien configurados. Por lo que se puede hacer es redirigir los emails a una cuenta local del servidor + instalar un servidor pop3 para que mi cuenta de gmail se descarge los emails del servidor.
DOVECOT
apt-get install dovecot-pop3d
/etc/dovecot/conf.d/10-auth.conf -> disable_plaintext_auth = no
/etc/dovecot/conf.d/10-master.conf -> inet_listener pop3s { port = 0 }
/etc/dovecot/conf.d/10-mail.conf -> mail_location = maildir:~/Maildir
Asi dejamos acceder al servidor por pop3 sin seguridad.
Configuramos postfix via /etc/postfix/virtual que entregue los correos a un usuario local sin permisos y sin capacidad de hacer login (/bin/false como shell). Configuramos la cuenta de google para que recupere por pop3 los mails de nuestro servidor de ese usuario.
Modificamos el script de firewall:
GOOGLE="64.18.0.0/20 64.233.160.0/19 66.102.0.0/20 66.249.80.0/20 72.14.192.0/18 74.125.0.0/16 173.194.0.0/16 207.126.144.0/20 209.85.128.0/17 216.58.208.0/20 216.239.32.0/19"
for ipgoogle in $GOOGLE
do
$ipt -A INPUT -i $EXTIF -s $ipgoogle -d $EXTIP -p tcp --dport 110 -j ACCEPT
done
Así solo dejamos acceder al pop3 desde los servidores de google.
Comentarios