HTTPSServer permite ejecutar un pequeño servidor HTTPS con la biblioteca estándar de Python. Conserva el modelo conocido de HTTPServer, pero añade la carga de un certificado y una clave privada para proteger las conexiones con TLS. Esto resulta útil en pruebas locales, integraciones, webhooks, laboratorios, demostraciones, herramientas internas y prototipos que necesitan HTTPS sin instalar un framework completo.
La comodidad no significa que http.server sea una plataforma de producción. No incorpora el endurecimiento, balanceo, supervisión, límites de recursos y protección frente a abuso que necesita un servicio público. La mejor forma de usarlo es dentro de entornos controlados, comprendiendo la exposición de red, los certificados, los handlers, la concurrencia y el cierre correcto.
Crear un servidor HTTPS básico
El constructor recibe la dirección, la clase que procesa las solicitudes, la ruta del certificado y la ruta de la clave privada. Vincular el servidor a 127.0.0.1 limita el acceso al equipo local.
from http.server import HTTPSServer, SimpleHTTPRequestHandler
server = HTTPSServer(
("127.0.0.1", 8443),
SimpleHTTPRequestHandler,
certfile="cert.pem",
keyfile="key.pem",
)
print("Servidor en https://127.0.0.1:8443")
server.serve_forever()
Usar 0.0.0.0 publica el puerto en todas las interfaces. Puede ser necesario en un laboratorio o contenedor, pero debe hacerse de forma deliberada y con reglas de firewall adecuadas.
Certificados para desarrollo
Un certificado autofirmado sirve para pruebas controladas. OpenSSL puede generar un certificado temporal:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout key.pem -out cert.pem -days 30 \
-subj "/CN=localhost"
Los clientes modernos validan Subject Alternative Names, por lo que conviene incluir los nombres y direcciones usados. Herramientas como mkcert simplifican certificados confiables en la máquina local. La clave privada no debe guardarse en el repositorio y necesita permisos restrictivos.
Crear un handler personalizado
El servidor gestiona las conexiones, mientras el handler construye las respuestas. Al heredar de BaseHTTPRequestHandler, puedes implementar rutas y métodos explícitos.
import json
from http.server import BaseHTTPRequestHandler, HTTPSServer
class ApiHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path != "/health":
self.send_error(404, "Ruta no encontrada")
return
body = json.dumps({"status": "ok"}).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
server = HTTPSServer(
("127.0.0.1", 8443),
ApiHandler,
certfile="cert.pem",
keyfile="key.pem",
)
server.serve_forever()
Define códigos de estado y cabeceras claros, limita el tamaño de las entradas y evita mostrar trazas o secretos. Las rutas, cabeceras y cuerpos deben considerarse datos no confiables.
Concurrencia con ThreadingHTTPSServer
El servidor básico procesa una solicitud cada vez. Una operación lenta puede bloquear a los demás clientes. ThreadingHTTPSServer crea un hilo por conexión y mejora la respuesta en pruebas concurrentes.
from http.server import ThreadingHTTPSServer, SimpleHTTPRequestHandler
server = ThreadingHTTPSServer(
("127.0.0.1", 8443),
SimpleHTTPRequestHandler,
certfile="cert.pem",
keyfile="key.pem",
)
server.serve_forever()
Los hilos introducen riesgos con el estado compartido. Protege objetos mutables, evita trabajo intensivo de CPU, configura timeouts y mantén los handlers breves. Un diseño de hilo por conexión también puede agotar recursos si demasiados clientes se conectan.
Configuración de ALPN
TLS puede anunciar protocolos de aplicación mediante ALPN. La lista debe coincidir con lo que el handler implementa. Anunciar HTTP/2 mientras el código solo entiende HTTP/1.1 provoca incompatibilidades. Para handlers comunes de http.server, HTTP/1.1 es la opción predecible.
Probar clientes con seguridad
Con un certificado autofirmado, curl -k es cómodo, pero desactiva la validación y debe limitarse al desarrollo local:
curl -k https://127.0.0.1:8443/health
Una prueba mejor confía de forma explícita en el certificado:
import ssl
import urllib.request
context = ssl.create_default_context(cafile="cert.pem")
with urllib.request.urlopen(
"https://localhost:8443/health",
context=context,
timeout=5,
) as response:
print(response.read().decode("utf-8"))
Desactivar globalmente la verificación TLS puede ocultar ataques de intermediario y terminar por accidente en producción.
Cierre seguro
Cierra el socket incluso cuando el proceso sea interrumpido:
try:
server.serve_forever()
except KeyboardInterrupt:
print("Cerrando servidor")
finally:
server.server_close()
En pruebas automatizadas, ejecuta el servidor en un hilo, llama a shutdown(), espera el hilo y después usa server_close(). Así evitas sockets abiertos y conflictos de puertos.
Límites y seguridad
Protege la clave, no registres cabeceras de autorización, restringe el directorio público, normaliza rutas, limita cuerpos y rechaza métodos no soportados. No publiques secretos del proyecto mediante SimpleHTTPRequestHandler. Si necesitas autenticación, rate limiting, renovación automática de certificados, proxy inverso, análisis endurecido o tráfico sostenido, utiliza un servidor de producción.
Consulta la documentación oficial de http.server y las recomendaciones de OWASP sobre TLS.
Casos adecuados
HTTPSServer funciona bien para receptores locales de webhooks, pruebas de SDK, redirecciones OAuth, validación de clientes TLS, intercambio temporal en redes confiables, laboratorios educativos y demostraciones reproducibles. No sustituye a un servidor endurecido para aplicaciones públicas.
Guías relacionadas
Continúa con contextlib.chdir, extracción segura con tarfile, ssl keylog_filename y zipfile.Path.
Conclusión
HTTPSServer simplifica una tarea frecuente: iniciar un servidor protegido por TLS sin envolver sockets manualmente. Su principal ventaja es la claridad para pruebas y aprendizaje. Usa una interfaz local, certificados adecuados, handlers pequeños, validación explícita, concurrencia cuidadosa y cierre fiable. Cuando los requisitos superen el entorno controlado, migra a una solución preparada para producción.







