Docs/ Seguridad/ Proteger su servidor sh0

Proteger su servidor sh0

Los mismos consejos esté donde esté alojado su servidor: ningún paso propio de un proveedor, solo lo que se ejecuta en la propia máquina.

Visión general

sh0 protege lo que sirve (HTTPS, secretos cifrados, roles), pero el servidor que lo aloja es suyo. La mayoría de los servidores comprometidos no lo son a través de la aplicación: se entra por SSH con una contraseña adivinada, o por un puerto que nadie quería exponer. Esta guía cierra esas puertas, en el orden que nunca le deja fuera. sh0 comprueba los mismos puntos por usted, en directo, en la página Seguridad del servidor del panel y con sudo sh0 doctor.

Antes de empezar

Mantenga abierta su sesión SSH actual hasta el final y pruebe cada cambio desde una NUEVA sesión. Desde su ordenador, compruebe que su clave abre una sesión sin contraseña:

bash
ssh -o PasswordAuthentication=no root@SERVER_IP

Si esa sesión pide una contraseña, aún no tiene ninguna clave en el servidor. Instale una y vuelva a probar:

bash
ssh-copy-id root@SERVER_IP

SSH: solo claves

Un servidor que acepta contraseñas SSH puede ser adivinado, y root es la primera cuenta que se prueba. Cuando su clave funcione, rechace las contraseñas:

bash
cat > /etc/ssh/sshd_config.d/00-sh0-hardening.conf <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
EOF
Note
El nombre del archivo empieza por 00- a propósito: sshd conserva el PRIMER valor que lee, y muchas imágenes incluyen un 50-cloud-init.conf que vuelve a activar las contraseñas. Un archivo llamado 99-… se ignoraría sin aviso.

Valide y luego recargue. Nunca reinicie sshd con un archivo que sshd -t rechaza; una recarga mantiene las sesiones abiertas. El servicio se llama ssh en Debian y Ubuntu, sshd en otros sistemas.

bash
sshd -t && systemctl reload ssh

Compruebe el valor efectivo para root desde una dirección externa y abra una nueva sesión con su clave antes de cerrar la actual:

bash
sshd -T -C user=root,host=check.invalid,addr=203.0.113.1 | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin) '

Cortafuegos y la trampa de Docker

Permita SSH, HTTP, HTTPS y el puerto del panel, y luego active ufw. Si SSH escucha en un puerto distinto del 22, permita ese puerto primero.

bash
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443
ufw allow 9000/tcp
ufw --force enable

El puerto 9000 sigue abierto mientras las direcciones *.sh0.app lleguen directamente a su servidor. Ciérrelo (sh0 serve --bind 127.0.0.1) solo cuando el panel se sirva en su propio dominio con HTTPS.

Warning
ufw no ve los puertos publicados por Docker: Docker escribe sus propias reglas iptables antes que las de ufw, de modo que una base de datos publicada en 5432 sigue accesible desde Internet con ufw activo. Docker reserva una cadena al administrador, DOCKER-USER. La regla siguiente solo deja pasar, desde la interfaz pública, las respuestas a conexiones abiertas por el servidor, y un pequeño servicio la vuelve a aplicar en cada arranque de Docker:
bash
cat > /usr/local/sbin/sh0-docker-user <<'EOF'
#!/bin/sh
# Docker-published ports: from the public interface, only replies get through.
IF=$(ip -o route get 1.1.1.1 | sed -n 's/.* dev \([^ ]*\).*/\1/p')
[ -n "$IF" ] || exit 1
iptables -C DOCKER-USER -i "$IF" -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN 2>/dev/null ||
  iptables -I DOCKER-USER 1 -i "$IF" -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
iptables -C DOCKER-USER -i "$IF" -j DROP 2>/dev/null ||
  iptables -I DOCKER-USER 2 -i "$IF" -j DROP
EOF
chmod 755 /usr/local/sbin/sh0-docker-user
cat > /etc/systemd/system/sh0-docker-user.service <<'EOF'
[Unit]
Description=sh0: filter Docker-published ports (DOCKER-USER)
After=docker.service
Requires=docker.service
PartOf=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/sh0-docker-user

[Install]
WantedBy=docker.service
EOF
systemctl daemon-reload
systemctl enable --now sh0-docker-user
iptables -S DOCKER-USER

Para mantener accesible un puerto publicado, añada una excepción antes de la regla DROP en /usr/local/sbin/sh0-docker-user:

bash
iptables -I DOCKER-USER 2 -i "$IF" -p tcp -m conntrack --ctorigdstport 5432 -j RETURN

Si su proveedor ofrece un cortafuegos de red delante del servidor, sea cual sea, úselo también: permita 22, 80, 443 (y 9000 mientras dependa de *.sh0.app) y rechace el resto. Filtra antes de que el tráfico llegue a la máquina, Docker incluido.

fail2ban

Con solo claves, los intentos no son peligrosos, pero llenan los registros. fail2ban bloquea las direcciones que insisten:

bash
apt-get install -y fail2ban python3-systemd
cat > /etc/fail2ban/jail.d/sh0-sshd.local <<'EOF'
[sshd]
enabled = true
backend = systemd
journalmatch = _COMM=sshd + _COMM=sshd-session
maxretry = 5
findtime = 10m
bantime = 1h
EOF
systemctl enable fail2ban
systemctl restart fail2ban
fail2ban-client status sshd

Actualizaciones y reinicios

Instale las actualizaciones de seguridad y deje que el sistema las instale automáticamente:

bash
apt-get update && apt-get upgrade
apt-get install -y unattended-upgrades && dpkg-reconfigure -plow unattended-upgrades

Cuando se actualiza el núcleo o una biblioteca esencial, la corrección solo se aplica tras un reinicio (existe /var/run/reboot-required). Planifíquelo en un momento de poco tráfico: sh0 se inicia de nuevo con el sistema.

El panel con HTTPS

Sin dominio propio, el panel se sirve en HTTP sin cifrar y la contraseña del propietario cruza la red sin cifrado. Apunte un registro DNS A al servidor y luego:

bash
sh0 panel-domain set panel.example.com

Que lo haga el instalador

En un servidor nuevo, el instalador aplica los pasos de SSH, cortafuegos y fail2ban anteriores cuando se le pide. Está desactivado por defecto; en una terminal, el instalador también hace la pregunta (sin respuesta en 30 segundos, es no).

bash
curl -fsSL https://get.sh0.dev | bash -s -- --harden
Note
El paso SSH solo se ejecuta si se encuentra una clave autorizada para la cuenta con la que está conectado; si no, se rechaza, con el motivo, y los demás pasos se ejecutan igualmente. sshd -t valida el archivo antes de cualquier recarga, y sshd nunca se reinicia.

Comprobar el resultado

La página Seguridad del servidor del panel (propietario y administradores) muestra estas comprobaciones en directo, con la corrección debajo de cada aviso; un punto en la navegación indica un aviso activo. Desde una terminal en el servidor:

bash
sudo sh0 doctor