Eligiendo tu Proveedor
La selección del proveedor depende de tres factores: latencia geográfica a tus usuarios, costo y calidad del soporte. Para la mayoría de proyectos pequeños a medianos, DigitalOcean, Hetzner y Vultr ofrecen la mejor relación precio-rendimiento. Hetzner en particular es un valor excepcional para tráfico europeo e internacional. AWS, GCP y Azure ofrecen más servicios pero a un costo y complejidad significativamente mayores.
Empieza con un plan un nivel por encima de tu necesidad actual. Sub-aprovisionar un servidor de producción y luego correr para redimensionarlo durante un pico de tráfico es una lección dolorosa. Es mucho más fácil reducir el tamaño una vez que tu línea base real es clara. Para la mayoría de aplicaciones web, 2 vCPU y 4 GB RAM es un punto de partida razonable.
Elige una región de centro de datos cercana a tu base de usuarios principal. Una latencia de ida y vuelta de 200ms vs. 20ms hace una diferencia perceptible en la capacidad de respuesta de las aplicaciones web. Para audiencias globales, necesitarás una CDN independientemente de la ubicación del servidor — pero el servidor de origen debería ser geográficamente razonable.
Hardening Inicial del Servidor
Primeras acciones después del aprovisionamiento: crear un usuario no-root con privilegios sudo, deshabilitar el inicio de sesión SSH de root y cambiar SSH a autenticación basada en claves. Estos tres pasos eliminan la mayoría de los ataques de fuerza bruta automatizados. Usa ssh-copy-id para instalar tu clave pública, luego edita /etc/ssh/sshd_config: PermitRootLogin no, PasswordAuthentication no.
Configura UFW (Uncomplicated Firewall): permite los puertos 22 (SSH), 80 (HTTP) y 443 (HTTPS). Deniega todo lo demás por defecto. Si ejecutas una base de datos, no expongas el puerto 3306 o 5432 a internet — usa tunelización SSH o una VPN para acceso remoto a la base de datos.
Instala fail2ban para bloquear automáticamente las IPs que fallan en la autenticación SSH repetidamente. Configúralo para bloquear después de 5 fallos en 10 minutos con una duración de bloqueo de 1 hora. Esto reduce dramáticamente el ruido de fuerza bruta en tus logs. También habilita las actualizaciones de seguridad automáticas: unattended-upgrades en Ubuntu/Debian maneja esto de forma transparente.
Configuración de Nginx + SSL/TLS
Nginx es la elección correcta para la mayoría de los despliegues en producción: alto rendimiento, excelente documentación y estabilidad probada. Instala desde el repositorio oficial de Nginx para la última versión estable, no el paquete predeterminado de la distribución que frecuentemente está significativamente desactualizado.
Configura SSL/TLS con Certbot y Let's Encrypt. Instala certbot y python3-certbot-nginx, luego ejecuta certbot --nginx -d tudominio.com -d www.tudominio.com. Certbot modifica automáticamente tu configuración de Nginx y configura la renovación automática. Verifica la renovación automática con: certbot renew --dry-run.
Endurece tu configuración TLS de Nginx: deshabilita SSLv3 y TLS 1.0/1.1, usa solo TLS 1.2 y 1.3. Configura ssl_ciphers en un conjunto de cifrado moderno (el Generador de Configuración SSL de Mozilla proporciona recomendaciones actuales). Habilita HSTS con un max-age largo. Añade cabeceras de seguridad: X-Frame-Options SAMEORIGIN, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin.
Automatización de Backups
La regla de los backups es simple: si no sucede automáticamente, no sucede. Los backups manuales se omiten durante los períodos de alta carga, que es precisamente cuando ocurren los desastres. Automatiza los volcados diarios de base de datos con un cron job que ejecute mysqldump (para MySQL) o pg_dump (para Postgres), comprima el output y lo envíe a una ubicación fuera del servidor.
Usa rclone para sincronizar backups al almacenamiento en la nube (S3, R2, Backblaze B2). Un cron job típico de backup: vuelca la base de datos, comprime con gzip con un nombre de archivo con timestamp, copia con rclone a tu bucket, luego elimina los backups locales de más de 7 días. Las copias en la nube deben retenerse durante 30+ días con reglas de ciclo de vida.
Prueba tus backups. Un backup del que nunca has restaurado es un backup que realmente no tienes. Programa una prueba de restauración mensual en un servidor de staging. Cronometra el procedimiento de restauración completo y documéntalo. Esto también valida que tus archivos de backup no estén corruptos y que tu runbook de restauración sea preciso.
CI/CD Básico
Un pipeline CI/CD simple para un proyecto alojado en VPS: al hacer push a main, tu CI (GitHub Actions, GitLab CI) ejecuta pruebas, construye assets, luego hace SSH al servidor y ejecuta un script de despliegue. El script de despliegue: git pull, instalar dependencias, ejecutar migraciones, recargar PHP-FPM o reiniciar tu proceso Node, limpiar cachés.
Los despliegues sin tiempo de inactividad requieren un poco más: desplegar a un nuevo directorio de release, ejecutar migraciones y pasos de calentamiento, luego intercambiar atómicamente un enlace simbólico de actual al nuevo release. Capistrano y Deployer implementan este patrón. Incluso una versión de script de shell es mejor que un git pull ingenuo que deja la aplicación en un estado roto a mitad del despliegue.
Mantén tus scripts de despliegue en control de versiones. Documenta el proceso de despliegue completo en un runbook. Cualquier miembro del equipo debería poder desplegar sin conocimiento tribal. Prueba el proceso de despliegue desde un checkout fresco al menos una vez por trimestre.
Monitoreo
Como mínimo, monitorea: tiempo de actividad del servidor (monitor de ping externo como UptimeRobot), uso del espacio en disco (alerta al 80%), CPU y memoria (alerta sobre uso alto sostenido) y tasa de error de la aplicación. Estos cuatro cubren los modos de fallo de producción más comunes.
Para el monitoreo a nivel de aplicación, integra un servicio de seguimiento de errores (Sentry es gratuito para pequeños volúmenes). Las excepciones no manejadas en producción deben crear alertas, no desaparecer silenciosamente en archivos de log que nadie lee. Configura Sentry para notificar mediante email o Slack sobre nuevos problemas.
Configura logrotate para todos los logs de aplicación y Nginx para evitar el agotamiento del disco. El logging estructurado (formato JSON) hace que los logs sean buscables y parseables por herramientas de agregación de logs. Incluso si no ejecutas un stack ELK completo, tener logs estructurados significa que puedes hacer grep efectivamente y migrar a un sistema de agregación de logs futuro sin reformatear.