Tutorial

Certificados SSL gratis con Let's Encrypt en un VPS

Seguridad y monitorización8 min de lectura4 pasos

El HTTPS ya no es opcional: navegadores, SEO y clientes lo exigen. En un VPS que usted controla de principio a fin, Let's Encrypt entrega certificados reconocidos, gratuitos y que se renuevan solos. Esta guía cubre la instalación paso a paso de certbot con Nginx, los certificados wildcard mediante Cloudflare DNS challenge, la verificación de la renovación automática con el timer de systemd, la supervisión de la expiración y los errores más frecuentes — rate-limits ACME, puerto 80 bloqueado, propagación DNS.

Contenido· Por qué gestionar Let's Encrypt usted mismo en un VPS1/10
  1. 01Por qué gestionar Let's Encrypt usted mismo en un VPS
  2. 02Lo que gana al autoalojar la cadena TLS
  3. 03Requisitos previos antes de empezar
  4. 04Instalar certbot y obtener un certificado Nginx
  5. 05Certificado wildcard con Cloudflare DNS challenge
  6. 06Hardening TLS en Nginx: TLS 1.2/1.3, HSTS y cipher suites
  7. 07Supervisar la expiración de los certificados
  8. 08Solución de problemas: rate-limits, puerto 80 bloqueado, propagación DNS
  9. 09Comparativa: certbot vs acme.sh vs Caddy HTTPS automático
  10. 10Probar antes de la producción

Por qué gestionar Let's Encrypt usted mismo en un VPS

Let's Encrypt es una autoridad de certificación gratuita que emite certificados TLS validados mediante un challenge automatizado (HTTP-01 o DNS-01). En un alojamiento compartido, usted sufre la configuración TLS del proveedor: versiones de protocolo impuestas, sin OCSP stapling, renovación opaca. En un VPS, usted controla certbot (o acme.sh), el reverse proxy y la terminación TLS. Usted decide los protocolos (solo TLS 1.2/1.3), las suites de cifrado, el HSTS y el grapado OCSP. También puede emitir un certificado wildcard (*.your-domain.com) mediante el challenge DNS-01, cubrir varios dominios en un solo certificado (SAN) y conectar la renovación a sus propias alertas. En resumen: un control total sobre la seguridad de transporte, condición para lograr una puntuación A+ en SSL Labs y la máxima confianza del lado del navegador.

Lo que gana al autoalojar la cadena TLS

  • Certificados 100% gratuitos, válidos 90 días y renovados automáticamente sin intervención.
  • Wildcard *.your-domain.com posible mediante el challenge DNS-01: un solo certificado para todos sus subdominios.
  • Control completo de la configuración: TLS 1.3, suites de cifrado modernas, HSTS y OCSP stapling.
  • Certificados SAN multidominio (your-domain.com, www.your-domain.com, api.your-domain.com) sobre una misma IP.
  • Renovación programable y observable: hooks de recarga, alertas por Slack o correo antes del vencimiento.
  • Sin dependencia de un panel de terceros: la misma receta funciona en todos sus VPS y entornos.

Requisitos previos antes de empezar

La terminación TLS consume muy pocos recursos: un VPS de 1 vCPU y 512 MB a 1 GB de RAM basta de sobra para servir el HTTPS de uno o varios sitios.

En cuanto a la red: su nombre de dominio debe apuntar a la IP pública del VPS (registro A/AAAA propagado). Compruebe la propagación antes de ejecutar certbot: dig +short your-domain.com debe devolver la IP de su VPS. Un challenge que falla por propagación DNS incompleta cuenta como intento y le acerca a los rate-limits de ACME.

Los puertos 80 y 443 deben estar abiertos en el firewall — el puerto 80 es indispensable para el challenge HTTP-01:

ufw allow 80/tcp
ufw allow 443/tcp
ufw reload

Para un certificado wildcard (*.your-domain.com), el challenge HTTP-01 no es suficiente: prevea un token API de su proveedor DNS (Cloudflare, OVH…) para automatizar el challenge DNS-01.

Instalar certbot y obtener un certificado Nginx

  1. Instalar certbot y el plugin Nginx

    En Debian/Ubuntu:

    apt update
    apt install -y certbot python3-certbot-nginx

    El plugin python3-certbot-nginx lee su configuración Nginx, inyecta la configuración TLS y reemplaza la directiva listen 80 por un bloque 443 ssl. Si prefiere gestionar Nginx manualmente, use --standalone o --webroot en lugar de --nginx.

  2. Apuntar el dominio y abrir los puertos

    Cree un registro A your-domain.com (y AAAA si usa IPv6) hacia la IP del VPS y luego autorice el tráfico web:

    ufw allow 80,443/tcp

    Confirme la resolución con dig +short your-domain.com antes de seguir adelante — un challenge siempre falla si el DNS todavía no apunta.

  3. Emitir el certificado con el plugin Nginx

    El método más directo — certbot modifica su vhost Nginx y gestiona la renovación:

    certbot --nginx -d your-domain.com -d www.your-domain.com

    Certbot pide una dirección de correo (alertas de vencimiento) y le invita a aceptar los términos de servicio. Emite el certificado, modifica /etc/nginx/sites-available/<vhost>, añade una redirección HTTP→HTTPS y recarga Nginx sin corte de servicio.

    Los archivos se depositan en /etc/letsencrypt/live/your-domain.com/: fullchain.pem (certificado + cadena) y privkey.pem (clave privada).

  4. Verificar la renovación automática

    Certbot instala un timer de systemd que intenta la renovación dos veces al día:

    systemctl status certbot.timer

    Para simular una renovación sin emitir un nuevo certificado:

    certbot renew --dry-run

    Si la simulación tiene éxito, su cadena de renovación está operativa. Asegúrese de que Nginx se recarga tras una renovación efectiva — certbot añade automáticamente un hook --deploy-hook "systemctl reload nginx" en /etc/letsencrypt/renewal/<domain>.conf al usar el plugin Nginx.

Certificado wildcard con Cloudflare DNS challenge

Un certificado *.your-domain.com cubre todos sus subdominios con un solo archivo. Es obligatorio si crea subdominios de forma dinámica o si no quiere emitir un certificado por subdominio.

El challenge HTTP-01 no puede validar un wildcard — necesita el challenge DNS-01, que requiere que certbot cree temporalmente un registro TXT _acme-challenge.your-domain.com.

Con Cloudflare (token de API):

apt install -y python3-certbot-dns-cloudflare

Cree un archivo de credenciales de Cloudflare (permisos: 600):

mkdir -p /etc/letsencrypt/cloudflare
chmod 700 /etc/letsencrypt/cloudflare
cat > /etc/letsencrypt/cloudflare/credentials.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
chmod 600 /etc/letsencrypt/cloudflare/credentials.ini

Emita el certificado wildcard:

certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
  -d your-domain.com \
  -d '*.your-domain.com'

Certbot crea el registro TXT, espera la propagación (10 segundos por defecto — aumentable con --dns-cloudflare-propagation-seconds 30), obtiene el certificado y luego elimina el registro TXT.

Alternativa con acme.sh:

acme.sh --issue --dns dns_cf -d your-domain.com -d '*.your-domain.com'

acme.sh utiliza la variable de entorno CF_Token o CF_Key + CF_Email según su método de autenticación de Cloudflare.

Hardening TLS en Nginx: TLS 1.2/1.3, HSTS y cipher suites

El plugin certbot configura un HTTPS funcional, pero la configuración por defecto no es óptima para una puntuación A+ en SSL Labs. Estas son las directivas que hay que añadir en su bloque server (o en un archivo incluido como /etc/nginx/snippets/ssl-params.conf):

# Protocolos: TLS 1.2 mínimo, TLS 1.3 recomendado
ssl_protocols TLSv1.2 TLSv1.3;

# Suites de cifrado modernas (Mozilla Intermediate)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;

# Sesión TLS
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

# HSTS (6 meses, subdominios incluidos, preload)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

# Cabeceras de seguridad adicionales
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

Redirija todo el puerto 80 hacia el 443 en un bloque server separado:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    return 301 https://$host$request_uri;
}

Recargue sin corte de servicio: nginx -s reload. Luego pruebe en SSL Labs — debería obtener A+.

Supervisar la expiración de los certificados

La renovación automática puede fallar en silencio: timer de systemd desactivado, puerto 80 bloqueado tras un cambio en el firewall, token de API de Cloudflare revocado… Un certificado caducado en producción interrumpe el servicio para todos sus visitantes.

Comprobación manual:

echo | openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null \
  | openssl x509 -noout -dates

Script de alerta por correo (para colocar en cron o systemd):

#!/bin/bash
# Alerta si el certificado expira en menos de 14 días
cert_file="/etc/letsencrypt/live/your-domain.com/fullchain.pem"
if ! openssl x509 -checkend 1209600 -noout -in "$cert_file" 2>/dev/null; then
  echo "ALERTA: certificado your-domain.com expira en menos de 14 días" \
    | mail -s "[SSL] Expiración inminente" [email protected]
fi

-checkend 1209600 corresponde a 14 días en segundos (14 × 86 400).

Con Uptime Kuma: añada un monitor de tipo «Certificate Expiry» que alerte a D-14 — sin scripts que mantener.

Solución de problemas: rate-limits, puerto 80 bloqueado, propagación DNS

Rate-limits ACME: «too many certificates already issued»
Let's Encrypt limita a 5 certificados por dominio registrable y por semana. Si alcanza este límite durante las pruebas, cambie al entorno de staging:

certbot --nginx --staging -d your-domain.com

El staging emite certificados no reconocidos por los navegadores, pero sin límite de tasa. Una vez validada su configuración, elimine el certificado de staging y vuelva a emitir en producción.

Puerto 80 bloqueado
El challenge HTTP-01 exige que Let's Encrypt acceda a http://your-domain.com/.well-known/acme-challenge/. Compruebe:

curl -I http://your-domain.com/.well-known/acme-challenge/test
# esperado: 404 (la ruta existe, el archivo todavía no)
ufw status | grep 80

Si el puerto 80 está bloqueado por un firewall externo (proveedor cloud, Cloudflare en modo proxy), ábralo temporalmente o cambie al challenge DNS-01.

Proxy de Cloudflare activo
Si su dominio está detrás de Cloudflare (icono de nube naranja), asegúrese de que el modo SSL de Cloudflare es Full (Strict) — en modo Flexible, Cloudflare se comunica con su servidor vía HTTP y nginx al redirigir HTTP→HTTPS produce un bucle infinito (HTTP 525/526).

Propagación DNS insuficiente
Para el challenge DNS-01, espere al menos 60 segundos tras crear el registro TXT antes de relanzar certbot. Compruebe:

dig TXT _acme-challenge.your-domain.com +short

Si el valor no aparece todavía, espere antes de volver a intentarlo.

Comparativa: certbot vs acme.sh vs Caddy HTTPS automático

Desplace la tabla

Criteriocertbotacme.shCaddy (HTTPS auto)
Instalación`apt install certbot`Script bash, sin dependencias del sistemaBinario único, incluido
Integración Nginx/ApachePlugin nativo (`--nginx`, `--apache`)Hooks `--install-cert` manualesGestiona su propio reverse proxy
Wildcard DNS-01Mediante plugin DNS (`python3-certbot-dns-*`)Nativo, muchos proveedores DNS integradosMediante módulo `tls.dns.*` (Caddy v2)
RenovaciónTimer de systemd (automático)Cron job generado en la instalaciónNativo, sin configuración
Curva de aprendizajeBaja — comandos intuitivosMedia — muchas opcionesMuy baja — Caddyfile minimalista
Caso de uso idealServidor Nginx/Apache dedicado existenteEntornos complejos, múltiples proveedores DNSProyectos nuevos, reverse proxy integrado

Probar antes de la producción

Antes de pasar a producción, pruebe contra el entorno de staging de Let's Encrypt (--staging en Certbot, --server letsencrypt_test en acme.sh): el límite de producción es de 5 emisiones por dominio y por semana, y un script mal ajustado puede hacerle chocar con él muy rápido.

Añada también una supervisión del vencimiento de los certificados: una sonda que ejecute openssl x509 -checkend 604800 (7 días) y dispare una alerta si la renovación automática ha fallado en silencio — un cron roto es la causa número uno de un HTTPS caducado en plena noche.

Consulte la página de releases de certbot en GitHub para verificar la versión disponible antes de escribir un tutorial o un script de instalación.

Despliegue su VPS Cloud con HTTPS listo para usar

La plantilla VPS Cloud de ServOrbit llega con Docker, un reverse proxy y la cadena Let's Encrypt preconfigurada: certificados emitidos y renovados automáticamente, y una puntuación A+ en SSL Labs desde el primer despliegue. Concéntrese en su aplicación, no en la infraestructura TLS.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva