Supervise la caducidad del certificado SSL con una API REST
Verifique las fechas de vencimiento, los emisores y los encabezados de seguridad del certificado SSL para cualquier dominio con dos puntos finales API. Incluye ejemplos de alertas de GitHub Actions, Node.js y Slack.
Un certificado SSL caducado desconecta su sitio y muestra una advertencia en el navegador que asusta clientes ausentes. Los certificados de Let's Encrypt se renuevan automáticamente, pero DNS mal configurado, trabajos cron fallidos, y los certificados manuales olvidados siguen provocando interrupciones. Necesita una forma de controlar el vencimiento fechas en todos sus dominios.
La API de botoi proporciona dos puntos finales para esto. Uno devuelve los detalles del certificado (emisor, fechas de validez, días hasta el vencimiento). El otro comprueba la compatibilidad con HTTPS y analiza la seguridad. encabezados. Juntos, cubren tanto el monitoreo de vencimientos como las auditorías de la postura de seguridad.
Obtenga detalles del certificado con /v1/ssl-cert/certificate
Este punto final se conecta al dominio, lee el certificado TLS y devuelve información estructurada. datos que puede analizar en cualquier idioma.
curl -X POST https://api.botoi.com/v1/ssl-cert/certificate \\
-H "Content-Type: application/json" \\
-d '{"domain": "stripe.com"}'
Respuesta:
{
"success": true,
"data": {
"domain": "stripe.com",
"subject": "CN=stripe.com",
"issuer": "C=US, O=Let's Encrypt, CN=E6",
"valid_from": "2026-02-18T00:00:00.000Z",
"valid_to": "2026-05-19T00:00:00.000Z",
"days_until_expiry": 51,
"serial": "04:A3:9B:7C:2D:1E:8F:00:5A:B2:C4:D6:E8:F0:12:34",
"fingerprint": "A1:B2:C3:D4:E5:F6:78:90:AB:CD:EF:01:23:45:67:89",
"san": ["stripe.com", "*.stripe.com"]
}
}
La days_until_expiry El campo es sobre el que crearás alertas. El
san matriz muestra todos los dominios que cubre el certificado, útil para verificar
que los certificados comodín incluyan los subdominios que espera.
Verifique el soporte HTTPS y los encabezados de seguridad con /v1/ssl
Saber que su certificado es válido no es suficiente. También quieres confirmar que la seguridad
Se han implementado encabezados como HSTS y CSP. El /v1/ssl El punto final maneja eso.
curl -X POST https://api.botoi.com/v1/ssl \\
-H "Content-Type: application/json" \\
-d '{"domain": "stripe.com"}'
Respuesta:
{
"success": true,
"data": {
"domain": "stripe.com",
"ssl_supported": true,
"protocol": "TLSv1.3",
"headers": {
"strict-transport-security": "max-age=63072000; includeSubDomains; preload",
"content-security-policy": "default-src 'self'; script-src 'self' js.stripe.com",
"x-frame-options": "SAMEORIGIN",
"x-content-type-options": "nosniff",
"referrer-policy": "strict-origin-when-cross-origin"
}
}
}
La ssl_supported boolean confirma que HTTPS funciona. El headers
superficies de objetos HSTS, CSP, X-Frame-Options, X-Content-Type-Options y Referrer-Policy.
Los encabezados que faltan indican lagunas en su configuración de seguridad. Un protocolo TLS por debajo de 1.2
es una señal de alerta.
Acciones de GitHub: verificación semanal de SSL con problemas creados automáticamente
Este flujo de trabajo se ejecuta todos los lunes, verifica una lista de dominios y abre un problema de GitHub si
cualquier certificado caduca dentro de los 30 días. Crear
.github/workflows/ssl-check.yml:
name: SSL Expiry Check
on:
schedule:
# Every Monday at 9:00 UTC
- cron: '0 9 * * 1'
workflow_dispatch:
jobs:
check-ssl:
runs-on: ubuntu-latest
steps:
- name: Check SSL certificates
run: |
DOMAINS=("stripe.com" "api.stripe.com" "dashboard.stripe.com")
THRESHOLD=30
FAILURES=""
for DOMAIN in "\\\${DOMAINS[@]}"; do
RESPONSE=\$(curl -s -X POST https://api.botoi.com/v1/ssl-cert/certificate \\
-H "Content-Type: application/json" \\
-d "{\\"domain\\": \\"\$DOMAIN\\"}")
DAYS=\$(echo "\$RESPONSE" | jq -r '.data.days_until_expiry')
ISSUER=\$(echo "\$RESPONSE" | jq -r '.data.issuer')
EXPIRY=\$(echo "\$RESPONSE" | jq -r '.data.valid_to')
echo "## \$DOMAIN" >> \$GITHUB_STEP_SUMMARY
echo "- Expires: \$EXPIRY" >> \$GITHUB_STEP_SUMMARY
echo "- Days left: \$DAYS" >> \$GITHUB_STEP_SUMMARY
echo "- Issuer: \$ISSUER" >> \$GITHUB_STEP_SUMMARY
echo "" >> \$GITHUB_STEP_SUMMARY
if [ "\$DAYS" -lt "\$THRESHOLD" ]; then
FAILURES="\$FAILURES\\n- \$DOMAIN expires in \$DAYS days (\$EXPIRY)"
fi
done
if [ -n "\$FAILURES" ]; then
echo "::error::Certificates expiring within \$THRESHOLD days:\$FAILURES"
exit 1
fi
echo "All certificates have more than \$THRESHOLD days remaining."
- name: Open GitHub issue on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'SSL certificate expiring soon',
body: 'The weekly SSL check found certificates expiring within 30 days. See the [workflow run](' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId + ') for details.',
labels: ['infrastructure', 'urgent']
});
El flujo de trabajo recorre cada dominio, consulta la API y acumula fallas. si
cualquier certificado cae por debajo del umbral de 30 días, falla el trabajo y crea un GitHub
problema etiquetado infrastructure y urgent. El resumen del trabajo muestra
el informe completo para cada dominio.
Ajustar DOMAINS y THRESHOLD para que coincida con su configuración. el libre
El nivel maneja hasta 100 solicitudes por día, lo que cubre ~14 dominios verificados semanalmente.
Node.js: monitorea múltiples dominios en un script
Para la integración en su propia pila de monitoreo, aquí tiene un script Node.js que verifica una serie de dominios en paralelo y certificados de indicadores próximos a caducar:
const DOMAINS = [
"stripe.com",
"api.stripe.com",
"dashboard.stripe.com",
"docs.stripe.com",
];
const THRESHOLD_DAYS = 30;
async function checkCert(domain) {
const res = await fetch("https://api.botoi.com/v1/ssl-cert/certificate", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
});
const { data } = await res.json();
return { domain, ...data };
}
async function checkAll() {
const results = await Promise.all(DOMAINS.map(checkCert));
const expiring = results.filter(
(r) => r.days_until_expiry < THRESHOLD_DAYS
);
console.log("SSL Certificate Report");
console.log("=".repeat(50));
for (const r of results) {
const status =
r.days_until_expiry < THRESHOLD_DAYS ? "WARNING" : "OK";
console.log(
\`[\\\${status}] \\\${r.domain} - \\\${r.days_until_expiry} days left (expires \\\${r.valid_to})\`
);
}
if (expiring.length > 0) {
console.log(
\`\\n\\\${expiring.length} certificate(s) expiring within \\\${THRESHOLD_DAYS} days.\`
);
}
return { results, expiring };
}
checkAll();
Ejecute esto en una programación cron o intégrelo en su canal de verificación de estado existente.
El Promise.all La llamada verifica todos los dominios al mismo tiempo, por lo que el total
El tiempo de ejecución se mantiene cerca de la latencia de una única llamada API.
Alerta de webhook de Slack cuando un certificado caduca pronto
Combine la verificación del certificado con un webhook entrante de Slack para notificar a su equipo cuando El certificado necesita atención:
async function sendSlackAlert(domain, daysLeft, validTo) {
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: \`:rotating_light: SSL certificate for \\\${domain} expires in \\\${daysLeft} days\`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: [
"*SSL Certificate Expiry Warning*",
\`Domain: \\\`\\\${domain}\\\`\`,
\`Days remaining: *\\\${daysLeft}*\`,
\`Expires: \\\${validTo}\`,
].join("\\n"),
},
},
],
}),
});
}
// After running the certificate check
async function checkAndAlert() {
const DOMAINS = ["stripe.com", "api.stripe.com"];
for (const domain of DOMAINS) {
const res = await fetch(
"https://api.botoi.com/v1/ssl-cert/certificate",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
}
);
const { data } = await res.json();
if (data.days_until_expiry < 30) {
await sendSlackAlert(domain, data.days_until_expiry, data.valid_to);
}
}
}
checkAndAlert();
El mensaje incluye el dominio, los días restantes y la fecha de vencimiento. Tu equipo ve el alerta en Slack y puede investigar antes de que caduque el certificado.
Auditoría de seguridad completa: combine ambos endpoints
Para obtener una imagen completa, ejecute ambos puntos finales en paralelo por dominio. esto te da datos de caducidad del certificado y cobertura del encabezado de seguridad en una sola pasada:
async function auditSsl(domain) {
const [cert, ssl] = await Promise.all([
fetch("https://api.botoi.com/v1/ssl-cert/certificate", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
}).then((r) => r.json()),
fetch("https://api.botoi.com/v1/ssl", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
}).then((r) => r.json()),
]);
const issues = [];
// Certificate checks
if (cert.data.days_until_expiry < 30) {
issues.push(\`Certificate expires in \\\${cert.data.days_until_expiry} days\`);
}
// Security header checks
const headers = ssl.data.headers || {};
if (!headers["strict-transport-security"]) {
issues.push("Missing HSTS header");
}
if (!headers["content-security-policy"]) {
issues.push("Missing Content-Security-Policy header");
}
if (!headers["x-frame-options"]) {
issues.push("Missing X-Frame-Options header");
}
return { domain, cert: cert.data, ssl: ssl.data, issues };
}
// Run audit across all domains
const domains = ["stripe.com", "api.stripe.com"];
Promise.all(domains.map(auditSsl)).then((results) => {
for (const r of results) {
console.log(\`\\n\\\${r.domain}:\`);
console.log(\` Certificate: \\\${r.cert.days_until_expiry} days left\`);
console.log(\` TLS: \\\${r.ssl.protocol}\`);
console.log(\` Issues: \\\${r.issues.length === 0 ? "None" : r.issues.join(", ")}\`);
}
});
Este script informa la caducidad del certificado, la versión del protocolo TLS y la falta de seguridad. encabezados para cada dominio. Agréguelo a su revisión de seguridad semanal o conéctelo a su Panel de respuesta a incidentes.
Puntos clave
-
/v1/ssl-cert/certificatedevuelve el emisor, fechas de validez,days_until_expiry, número de serie, huella digital y lista SAN para cualquier certificado TLS del dominio. -
/v1/sslcomprueba la compatibilidad con HTTPS, informa la versión del protocolo TLS y explora HSTS, CSP, X-Frame-Options, X-Content-Type-Options y Referrer-Policy encabezados. -
Ambos puntos finales funcionan de forma anónima a 5 solicitudes por minuto. pasar un
X-Api-Keyencabezado para límites más altos. - Un trabajo cron semanal de GitHub Actions con un umbral de 30 días detecta fallas de renovación antes de que se conviertan en cortes.
- Combine ambos puntos finales para ejecutar la supervisión de la caducidad del certificado y el encabezado de seguridad auditorías en un solo script.
FAQ
- ¿Cómo verifico la caducidad del certificado SSL a través de API?
- Envíe una solicitud POST a https://api.botoi.com/v1/ssl-cert/certificate con un cuerpo JSON que contenga el dominio. La respuesta incluye los campos valid_from, valid_to y days_until_expiry del certificado. No se necesita CLI de openssl ni inspección manual del navegador.
- ¿Cuál es la diferencia entre /v1/ssl-cert/certificate y /v1/ssl?
- El punto final /v1/ssl-cert/certificate devuelve detalles del certificado: emisor, asunto, número de serie, fechas de validez y días hasta el vencimiento. El punto final /v1/ssl comprueba si se admite HTTPS y escanea encabezados de seguridad como HSTS, CSP, X-Frame-Options y Referrer-Policy. Utilice el primero para monitorear la caducidad y el segundo para auditorías de seguridad.
- ¿Puedo consultar certificados SSL sin una clave API?
- Sí. El acceso anónimo permite 5 solicitudes por minuto y 100 solicitudes por día con limitación de velocidad basada en IP. No se requiere registro ni clave API. Para un mayor rendimiento, los planes pagos comienzan en $9/mes.
- ¿Con qué frecuencia debo comprobar la caducidad del certificado SSL?
- Semanal es una buena base para la mayoría de los equipos. Los certificados Let's Encrypt se renuevan cada 90 días con renovación automática 30 días antes de su vencimiento. Una verificación semanal con un umbral de advertencia de 30 días le brinda tiempo suficiente para corregir fallas de renovación antes de que caduque el certificado.
- ¿Funciona esto con certificados internos o autofirmados?
- La API se conecta al dominio a través de la Internet pública, por lo que funciona con cualquier certificado servido en el puerto 443. Los certificados autofirmados devolverán detalles del certificado, pero el campo del emisor mostrará la entidad autofirmada en lugar de una CA confiable.
Empieza a construir con botoi
150+ endpoints de API para consultas, procesamiento de texto, generacion de imagenes y utilidades para desarrolladores. Plan gratuito, sin tarjeta de credito.