Este artículo no está completo, pero ya es válido para iniciar un servidor VPS.
Intentaremos completar (en algún momento del futuro) las secciones:
Configuración simple de cortafuegos con nftables
Configuración simple de cortafuegos con firewalld
En la siguiente entrega veremos como configurar Traefik como proxy inverso.
Describimos la instalación de un VPS en el proveedor Contabo, pero quitando los detalles particulares de ese proveedor el resto de los pasos se pueden aplicar a cualquier VPS con Debian 12 Server
Opciones en Contabo
Escogemos un servidor sencillo sin opciones extra.
Sistema Operativo
Debian 12 Server
Tipo de servidor
Cloud VPS 1
Cores
4 vCPU
Memoria
6 Gb RAM
HD
400 Gb
En el proceso de instalación especificamos que queremos Debian 12
Es importante recordar la password de root aunque ahora hay una opción para resetearla desde la web de contabo
ATENCIÓN: Evita usar caracteres especiales y las letras ‘y’ y ‘z’ al establecer la password de root. Hay un problema con los LOCALES y con el mapa de teclado que solucionaremos más tarde
Los snapshots de los servidores se borran a los 30 dias
En el panel de control web, sección Your Services debajo del botón Manage tenemos la opción para asignarle un nombre al servidor, yo lo hago con todos por que me es más sencillo recordarlos e interpretar las facturas
Si hay problemas tendrás que recurrir al acceso via VNC. En la web de control de servidores en Contabo tienes la info para conectarte al VNC. Tienes que poner una contraseña para acceder al servidor VNC que contenga mayúsculas, minúsculas, números y tenga EXACTAMENTE ocho caracteres. Puedes dejar el acceso VNC desactivado y activarlo solo cuando lo necesitas.
Instalación
Actualización de paquetes
Con nuestro S.O. escogido (Debian 12) recién instalado en el VPS nos conectamos desde nuestro PC.
En mi estación de trabajo (desde donde me conecto a mis servidores) tengo configurado el acceso ssh via claves GPG. Si haces como yo y usas distintas claves por cada servidor remoto es posible se acumulen tantas claves que la conexión falle con el error Too many authentication failures. Esto ocurre por que ssh irá probando todas las claves disponibles para la conexión. Como el servidor aun no está configurado para aceptar claves fallarán todos los intentos de conexión, aparecerá el error y el servidor remoto rechazará la conexión. Para evitar eso usamos la opción:
Preferredauthentications=password
Otra forma de conectarse sería:
ssh -o IdentitiesOnly=yes root@<vps_ip_address>
Y hacemos la típica actualización de todos los paquetes:
1
2
apt update
apt upgrade
Lo más seguro es que nos de un fallo de locale settings de este estilo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
perl: warning: Please check that your locale settings:
LANGUAGE = "en_GB:en",
LC_ALL = (unset),
LC_TIME = "es_ES.UTF-8",
LC_MONETARY = "es_ES.UTF-8",
LC_ADDRESS = "es_ES.UTF-8",
LC_TELEPHONE = "es_ES.UTF-8",
LC_NAME = "es_ES.UTF-8",
LC_MEASUREMENT = "es_ES.UTF-8",
LC_IDENTIFICATION = "es_ES.UTF-8",
LC_NUMERIC = "es_ES.UTF-8",
LC_PAPER = "es_ES.UTF-8",
LANG = "en_GB.UTF-8"
are supported and installed on your system.
Lo arreglamos en la siguiente sección.
Reconfigurar locales y mapa de teclado
Reconfiguramos los locales:
1
dpkg-reconfigure locales
Dejamos el en_US.UTF-8 como locale por defecto.
Aparentemente Debian 12 ha pasado a controlar los locales bajo systemd. Parece que hay conflictos, por que el antiguo comando locale nos dice una cosa y el nuevo comando localectl status nos dice otra:
locale -a # Lista de los locales que he generado con dpkg-reconfigure localesC
C.utf8
en_GB.utf8
en_US.utf8
es_ES.utf8
eu_ES.utf8
gl_ES.utf8
POSIX
locale # Antiguo comando para ver la configuración de localesLANG=en_GB.UTF-8
LANGUAGE=en_GB:en
LC_CTYPE="en_GB.UTF-8"LC_NUMERIC=es_ES.UTF-8
LC_TIME=es_ES.UTF-8
LC_COLLATE="en_GB.UTF-8"LC_MONETARY=es_ES.UTF-8
LC_MESSAGES="en_GB.UTF-8"LC_PAPER=es_ES.UTF-8
LC_NAME=es_ES.UTF-8
LC_ADDRESS=es_ES.UTF-8
LC_TELEPHONE=es_ES.UTF-8
LC_MEASUREMENT=es_ES.UTF-8
LC_IDENTIFICATION=es_ES.UTF-8
LC_ALL=localectl status # Nuevo comando para ver la configuración de localesSystem Locale: LANG=en_US.UTF-8
LANGUAGE=en_GB:en
VC Keymap: (unset) X11 Layout: de
X11 Model: pc105
En cualquier caso ya no nos aparecerán más errores de locales al hacer instalaciones de paquetes, pero tenemos que solucionar también el problema del mapa de teclado que nos interfiere al conectarnos via VNC desde la página web de administración de Contabo. Para ello ejecutamos dpkg-reconfigure keyboard-configuration, escogiendo las opciones (dependen del teclado que uses):
Keyboard model: Generic 105-key PC
Country of origin: Spanish
Keyboard Layout: Spanish
Altgrn key: Default
Compose key: No compose key
Después de reconfigurar ya tendremos el mapa correcto :
1
2
3
4
5
6
localectl status
System Locale: LANG=en_US.UTF-8
LANGUAGE=en_GB:en
VC Keymap: (unset) X11 Layout: es
X11 Model: pc105
Con esto no deberíamos tener ya problemas para hacer login con el VNC sea cual sea la contraseña de nuestro usuario root.
Contraseñas
Una vez que compruebes que el teclado funciona bien via VNC y que la configuración de locales ya no te da problema puedes cambiar las contraseñas y poner la que quieras. Pero en los siguientes pasos vamos a prohibir el acceso de root y vamos a exigir que el acceso por ssh se haga con claves GPG.
Eso si, por VNC desde la página de administración de Contabo, siempre podrás entrar como root.
Instalación de git y etckeeper
git lo uso continuamente, etckeeper se encarga de mantener todos los cambios que haya en el directorio /etc/ de nuestro servidor controladas con git. A mi ya me ha resultado muy útil para resolver un par de problemas causados por cambios de configuración o instalación de paquetes. Uso el etckeeper estrictamente en local, nunca he definido un remote para este repo de git.
git-crypt y gnupg son una manera de almacenar información confidencial en un repo de git. Aunque gnupg vale para muchas más cosas y merece la pena tenerlo instalado.
Instalamos git y etckeeper (los siguientes comandos hay que ejecutarlos como root para tener el git configurado para etckeeper):
1
2
3
4
5
6
apt install git
apt install git-crypt
apt install gnupg
git config --global user.email "whatever@mail.com"# Pon el correo que te convengagit config --global user.name "Name Surname"# Pon el nombre de usuario que tu quierasapt install etckeeper
Instalación de utilidades
Bibliotecas de compresión:
1
apt install zip unzip unace bzip2 lzop p7zip p7zip-full
Utilidades:
1
apt install most mc tree tmux aptitude rsync fasd
Instalamos sudo:
1
apt install sudo
Instalamos ufw
1
apt install ufw
Instalamos zsh:
1
apt install zsh
Instalamos emacs:
1
apt install emacs-nox
El comando completo de instalación sería:
1
2
3
apt install zip unzip unace bzip2 lzop p7zip p7zip-full \
most mc tree tmux aptitude rsync fasd \
sudo ufw zsh emacs-nox
Creación de usuarios en el VPS
Vamos a añadir usuarios (lo de los id de los usuarios son costumbres mias que no tienen justificación clara):
1
2
3
4
5
6
7
8
adduser --uid=1111 hostadmin # Siempre asigno el mismo id a los usuarios de administracióngpasswd -a hostadmin sudo
adduser salvari # Por costumbre dejo un usuario personal con id 1000gpasswd -a salvari sudo
adduser dockadmin # Acostumbro a tener el dockadmin en el id 1001gpasswd -a dockadmin sudo
Conexión al VPS via ssh
ssh en el cliente
En nuestra estación de trabajo preparamos las claves de acceso al server remoto y las trasferimos al mismo. Lo dos primeros comandos son de ejemplo, con una sola clave del tipo que sea te vale.
1
2
3
4
5
ssh-keygen -b 4096 -t rsa # Especificamos ~/.ssh/<serverName>_rsa como salidassh-keygen -t ed25519 -a 100# <-- Opción mas robusta (especificamos como salida ~/.ssh/<serverName>_ed25519)ssh-copy-id -i .ssh/<serverName>_ed25519 -o PreferredAuthentications=password remoteuser@host
Para dejar correctamente configurado el acceso ssh al VPS desde nuestra estación de trabajo, tenemos que configurar nuestro cliente ssh editando el fichero ~/.ssh/config. Hay también un fichero global con opciones para el cliente ssh que sería /etc/ssh/ssh_config. Los dos ficheros tienen el mismo formato.
1
2
touch ~/.ssh/config # Creamos el fichero si no existechmod 600 ~/.ssh/config # Solo nuestro usuario puede verlo, esto es imprescindible, ssh es muy susceptible
Editamos el fichero que tendría este contenido (evidentemente tienes que usar tus propias direcciones ip y ficheros de claves)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# This options deactivates the use of every key in the ssh-agent
# Only the keys specified in this file will be used
# Host *
# IdentitiesOnly=yes
Host firstvps
HostName <firstvps_ip_address>
User <user_name>
Port 22
IdentityFile ~/.ssh/firstvps_rsa
Host <secondvps_ip_address>
HostName <secondvps_ip_address>
User <user_name>
Port 22
IdentityFile ~/.ssh/secondvps_rsa
Con esta configuración y una vez configurado el ssh en el servidor (ver siguiente apartado) el comando de conexión será simplemente:
ssh <serverName>
Puedes conectarte a distintos usuarios en el lado VPS siempre y cuando hayas copiado la clave pública correspondiente al fichero ~/.ssh/authorized_keys de ese usuario remoto.
Configuración del servidor ssh en el VPS
En nuestro servidor VPS cambiamos la configuración para que:
No se admitan login via ssh con password (¡OJO! Esta es la opción que tendrás que habilitar de nuevo si te lias con tus claves gpg para ssh)
No se admita login via ssh con el usuario root
Tenemos que editar el fichero de configuración /etc/ssh/sshd_config. A continuación los cambios introducidos
...# 20240619-salvari uncommentPubkeyAuthenticationyes...# To disable tunneled clear text passwords, change to no here!# 20240619-salvari changed to noPasswordAuthenticationno#PermitEmptyPasswords no...# 20240619-salvari changed to noUsePAMno...# 20240619-salvari changed to noPermitRootLoginno
Después de cambiar la configuración reiniciamos el servicio con sudo systemctl restart ssh
Ahora tenemos que comprobar que podemos conectarnos desde nuestra estación de trabajo via clave gpg, por ejemplo con el comando que ya describimos: ssh <serverName>
Configuración del cortafuegos
Ya hace tiempo que en Linux se ha pasado de implementar los firewall con iptables a usar nftables. Para mantener la compatibilidad con el antiguo iptables hay utilidades que se encargan de traducir los comandos iptables a configuraciones con nftables
Yo solía usar Uncomplicated Firewall (UFW) para configurar mis cortafuegos por que mi configuración era muy simple. El problema es que UFW sigue usando comandos iptables y no se si la traducción a nftables queda muy elegante así que aunque de momento lo dejemos con UFW voy a echar un ojo a la configuración directa con nftables y también a usar Firewalld en lugar de UFW.
Las ventajas de usar directamente nftables son configuraciones más simples y que aprendes como usuar nftables y como funciona un cortafuegos.
La principal ventaja de usar UFW o Firewalld es que los escenarios y aplicaciones típicos son muy fáciles de configurar.
UFW
Habíamos instalado ufw al instalar las utilidades al principio. Ahora vamos a poner la configuración básica del cortafuegos, es decir, vamos a permitir exclusivamente conexiones via ssh:
1
2
3
4
5
6
7
sudo ufw status verbose # Comprobamos que está deshabilitadosudo ufw app list # comprobamos que apps soportasudo ufw default deny incoming # le decimos que por defecto no acepta nada entrantesudo ufw default allow outgoing # por defecto permitimos conexiones salientessudo ufw allow ssh # permitimos conexiones sshsudo ufw enable# lo habilitamossudo ufw status verbose # vemos el estado del cortafuegos
La respuesta al último comando tendrá esta pinta:
1
2
3
4
5
6
7
8
9
Status: active
Logging: on (low)Default: deny (incoming), allow (outgoing), disabled (routed)New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
Según vayamos añadiendo servicios tendremos que ir añadiendo reglas al firewall.
Si queremos ver como queda esto configurado en nftables podemos ejecutar el comando sudo nft list ruleset. Antes de activar el cortafuegos el comando no devuelve nada puesto que no hay definida ninguna regla. Pero tras activarlo obtenemos la configuración de reglas que figura a continuación. Son muchísimas reglas para lo que queremos (permitir sólo el acceso via ssh) Es de suponer que el UFW deja todo preparado para añadir nuevas reglas en el futuro. Aun así si configuramos lo mismo directamente con comandos nftables dudo mucho que necesitemos más de 30 lineas para dejar todo programado y bien comentado en el fichero de configuración.
Si queremos ver el cortafuegos en acción podemos ejecutar el comando sudo journalctl -S today |grep UFW, la cantidad de intentos de acceso bloqueados nunca deja de asombrarme.
Instalación y configuración de fail2ban
Instalación de fail2ban
Primero necesitamos instalar fail2ban en nuestro VPS. Podemos usar simplemente:
1
sudo apt install fail2ban
Si por lo que sea queremos instalar la última versión, podemos hacerlo descargándola desde aquí con los siguientes comandos:
# Echa un ojo al repo de releases y apunta la versión actual de fail2ban# En nuestro caso es: https://github.com/fail2ban/fail2ban/releases/download/1.1.0/fail2ban_1.1.0-1.upstream1_all.debcd /tmp/
# 1) download deb package and signature:wget https://github.com/fail2ban/fail2ban/releases/download/1.1.0/fail2ban_1.1.0-1.upstream1_all.deb \
https://github.com/fail2ban/fail2ban/releases/download/1.1.0/fail2ban_1.1.0-1.upstream1_all.deb.asc
# 2) check signature (if you want to be sure file is unmodified):gpg --verify fail2ban_1.1.0-1.upstream1_all.deb.asc fail2ban_1.1.0-1.upstream1_all.deb
# 3) view details of the package:dpkg -I fail2ban_1.1.0-1.upstream1_all.deb
# 4) to ensure the upgrade run gentler (protocol of previous version may be incompatible), stop fail2ban before install:# using service:sudo service fail2ban stop
# using client:sudo fail2ban-client stop
# 5a) either install package using dpkg (standalone package, don't regard dependencies):sudo dpkg -i fail2ban_1.1.0-1.upstream1_all.deb
# if the package introduces some "broken" dependencies (I don't think so in case of fail2ban which has few dependencies),# to fix the unmet dependency issue, run this:sudo apt -f install
# 5b) alternatively install package using gdebi (that will take care of installation of dependencies):sudo gdebi fail2ban_1.1.0-1.upstream1_all.deb
# if you want to check anyway whether there are some broken packages and fix them automatically, you can run:sudo apt -f install
Una vez instalado fail2ban podemos comprobar el estado del servicio:
1
2
systemctl list-units -a --state=active --type=service
systemctl status fail2ban.service
Configuración de fail2ban
Hay dos ficheros principales de configuración en fail2ban: /etc/fail2ban/fail2ban.conf y /etc/fail2ban/jail.conf (ver aquí)
/etc/fail2ban/fail2ban.conf
Es el fichero de configuración de las opciones de operación del demonio fail2ban. Aquí se especifican cosas como el loglevel, el fichero de log, el socket o el fichero del pid.
/etc/fail2ban/jail.conf
Este es el fichero interesante, aquí es donde configuramos las reglas de baneado. Así aquí se configura, por ejemplo, el intervalo de baneo, el número de intentos de login antes de banear una ip, la lista blanca de IPs, la info que se envia por correo cuando se detecta un ataque, etc. etc.
En fail2ban definimos un jail por cada servicio que nos interesa proteger.
En casi todos los sitios que he leido nos aconsejan es hacer copias de los dos ficheros con extensión .local y hacer la configuración en estas copias.
1
2
3
cd /etc/fail2ban/
cp fail2ban.conf fail2ban.local
cp jail.conf jail.local
Pero la verdad es que en el man de fail2ban nos dicen que en los ficheros .local pongamos exclusivamente lo que no coincida con los valores por defecto. Y así lo voy a configurar.
Cambio de ficheros de logs en Debian 12
Debian 12 ha cambiado la forma de gestionar los logs del sistema, ahora se usa journald bajo el paragüas de systemd. Si echais un ojo al directorio /var/log comprobareis que ya no existen la mayoria de los ficheros de log tradicionales.
Esto impacta directamente en la configuración de fail2ban. Hay que tenerlo en cuenta por que con las configuraciones típicas de ejemplo en internet (o mi antigua configuración) ya no funciona.
Otro detalle de la configuración de fail2ban es que la mayoría de los linux actuales han cambiado del antiguo iptables a nftables para implementar las políticas de cortafuegos. Este cambio no es reciente pero yo no era muy consciente por que hay programas de “traducción” de reglas iptables a reglas nftables . Si investigas un poco en tu linux seguramente verás que cuando invocas iptables casi seguro que en realidad estás invocando a xtables-nft-multi.
Este no es un problema que impida el funcionamiento de fail2ban. Por ejemplo, ya comentamos que el cortafuegos que hemos instalado en nuestro server (Uncomplicated Firewall o ufw) sigue usando iptables y lo mismo hacen muchas otras aplicaciones como Docker sin ir más lejos. Asi que si no cambiamos la configuración por defecto fail2ban también usaría comandos de iptables que serían traducidos por xtables-nft-multi. Pero creo que lo conveniente es usar ya nftables puesto que fail2ban lo soporta. 1
Si desplegamos fail2ban por primera vez hay que ir con cuidado de que no nos bloquee a nosotros mismos fuera del sistema. Puede que quieras activar el acceso con password via ssh antes de hacer el despliegue de fail2ban y seguramente es mejor no desplegar políticas de baneo muy agresivas hasta comprobar que todo funciona bien.
Si antes de activar fail2ban quereis ver la cantidad de intentos de acceso ilegales2 que tiene vuestro VPS podéis ejecutar:
1
2
journalctl -u ssh.service -S today
journalctl -u ssh -S "1 hour ago"q # Limitado a la última hora, el parámetro u (unit) acepta regexp
Con todas estas consideraciones nuestro fichero jail.local inicial quedaría:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[DEFAULT]# Add my others VPS as trusted serversignoreip=xxx.xxx.xxx.xxxyyy.yyy.yyy.yyybanaction=nftables[type=multiport]# banaction=nftables[type=allports] # optional, more aggresive## JAILS#[sshd]enabled=truebackend=systemd# backend is systemd in Debian 12
En este fichero de configuración:
Añado mis otros VPS a la lista ignoreip para que fail2ban nunca los banee. (Evidentemente para acceder tendre que configurar correctamente las claves ssh en esos otros VPS)
Cambio el banaction para que fail2ban use nftables en lugar de iptables
Activo un jail para el servicio sshd y, muy importante, especifico que el backend es systemd
Una vez configurado reiniciamos el servicio *fail2ban con:
1
sudo systemctl restart fail2ban
Con esta parametrización estas son las ip baneadas a los pocos minutos de arrancar el servicio.
1
2
3
4
5
6
7
8
9
10
11
fail2ban-client status sshd
Status for the jail: sshd
|- Filter
||- Currently failed: 18||- Total failed: 159|`- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 18|- Total banned: 18`- Banned IP list: 47.236.2.29 8.219.246.145 8.222.245.20 47.237.106.242 8.222.169.164 8.219.241.126 8.222.184.144 8.222.150.15 171.22.31.29 202.157.184.46 103.146.52.138 103.142.87.225 47.245.92.217 35.192.179.181 27.71.237.15 47.237.4.213 160.20.186.237 59.34.217.89
root@vmi1540613:/etc/fail2ban#
También podemos comprobar la regla añadida por fail2ban a la configuración de nuestro firewall3:
[DEFAULT]# Add my others VPS as trusted serversignoreip=xxx.xxx.xxx.xxxyyy.yyy.yyy.yyymaxretry=2findtime=60mbantime.increment=truebantime=60mbanaction=nftables[type=multiport]#banaction_allports = nftables[type=allports]## JAILS#[sshd]enabled=true# To use more aggressive sshd modes set filter parameter "mode" in jail.local:# normal (default), ddos, extra or aggressive (combines all).# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.#mode = normalport=sshlogpath=%(sshd_log)s# backend = %(sshd_backend)sbackend=systemd
Otras jail
Evidentemente a medida que vayamos instalando servicios en nuestro VPS deberemos añadir las jail necesarias para que fail2ban monitorice intentos de acceso ilegal a esos servicios.
Instalación de zsh
Me gusta usar zsh para trabajar en la terminal así que lo vamos a instalar en nuestro VPS.
Antes de empezar vamos a instalar:
python3-all-dev aunque sólo lo necesitas si vas a usar pyenv para gestionar entornos virtuales de Python3
antigen para gestionar todos los plugins de zsh
zsh-git-prompt para tener información de git en el prompt del sistema
En el home de cada usuario (cada usario con el que queramos usar zsh) tendremos que crear un fichero ~/.zshrc con las opciones de zsh que queramos para ese usuario y un fichero ~/.zalias.zsh con los alias que queramos definir.
Con esto tendríamos el Docker instalado en nuestro VPS. Para comprobarlo deberíamos ejecutar con nuestro usuario dockadmin el contenedor de pruebas con: