Tutorial

Python 3.10 sin soporte: migrar sus aplicaciones en un VPS

Desarrollo9 min de lectura7 pasos

Python 3.10 llegó al fin de vida en octubre de 2026: ya no se publica ninguna corrección de seguridad para esta rama. Su aplicación Django o FastAPI sigue respondiendo, y nada indica que el intérprete esté congelado. El riesgo se acumula en silencio y la migración parece más pesada con cada mes de retraso. Este es un método que no toca lo existente: un segundo entorno con Python 3.12 junto al primero, dependencias bloqueadas y probadas, y un cambio reversible en una sola línea.

Contenido· Qué cambia con el fin de vida de Python 3.101/14
  1. 01Qué cambia con el fin de vida de Python 3.10
  2. 02Lo que cuesta un intérprete congelado
  3. 03Calendario de soporte de las ramas de Python
  4. 04Qué versión de destino elegir
  5. 05Saber qué intérprete sirve realmente la producción
  6. 06Requisitos antes de empezar
  7. 07Migrar sin interrumpir el servicio
  8. 08Cambiar y volver atrás en una línea
  9. 09Los puntos de rotura que hay que revisar
  10. 10Lista de control antes del cambio
  11. 11Solución de problemas: los errores que se repiten
  12. 12Mensaje observado y remedio
  13. 13Fijar el destino, no solo migrar
  14. 14Hacer de la subida de versión un gesto habitual

Qué cambia con el fin de vida de Python 3.10

La guía del desarrollador de Python publica el calendario de cada rama. Python 3.10, lanzada en octubre de 2021, figura allí como fin de vida desde el 1 de octubre de 2026. En la práctica, la rama ya no recibe ninguna corrección, ni siquiera de seguridad: un fallo descubierto en el intérprete o en su biblioteca estándar seguirá abierto.

Su código sigue funcionando y sus pruebas pasan, y eso es lo que hace engañosa la situación. El fin de vida no rompe nada el mismo día. Retira la red de seguridad para todos los días siguientes, mientras las distribuciones, las imágenes base y las bibliotecas de terceros se desentienden poco a poco.

Lo que cuesta un intérprete congelado

  • Fallos sin corrección — toda vulnerabilidad del intérprete publicada tras el fin de vida sigue abierta en la rama 3.10; solo una subida de versión la cierra.
  • Dependencias que se descuelgan — tarde o temprano las bibliotecas suben su versión mínima de Python; una instalación nueva acaba resolviendo versiones antiguas, o fallando.
  • Imágenes base congeladas — una imagen de contenedor construida sobre la rama 3.10 descansa en un intérprete sin correcciones de origen, y sus análisis de vulnerabilidades lo señalan en cada build.
  • Auditorías bloqueadas — un intérprete sin soporte es una línea roja en las revisiones de seguridad y los cuestionarios de proveedores de sus clientes.
  • Migración forzada — de 3.10 a 3.12 hay dos versiones menores de diferencia; cuanto más espere, más larga la lista de roturas, y un proyecto planificado cuesta menos que una urgencia tras un incidente.

Calendario de soporte de las ramas de Python

Desplace la tabla

VersiónFin de soporteLectura para su VPS
3.9octubre de 2025Sin soporte desde hace más de un año: abandónela sin esperar
3.10octubre de 2026Sin soporte desde el 1 de octubre: ninguna corrección más
3.11octubre de 2027Escalón mínimo: resuelve el problema de hoy, no el del año próximo
3.12octubre de 2028Destino recomendado: dos años de margen y un ecosistema asentado
3.13octubre de 2029Con soporte aún más largo; adóptela cuando sus dependencias estén validadas
3.14octubre de 2030Rama más reciente de esta tabla, con el fin de soporte más lejano

Qué versión de destino elegir

Python 3.12 es el destino que recomendamos para una aplicación existente: su fin de soporte está previsto para octubre de 2028, dos años de margen, y los frameworks habituales la admiten. Python 3.11 es un escalón mínimo que le devuelve a la misma migración en octubre de 2027.

Python 3.13 tiene soporte aún más largo, hasta octubre de 2029. No la consideramos inadecuada: solo supone que cada una de sus dependencias publique paquetes para esa versión, algo que se comprueba en su entorno de pruebas. Recordatorio de la guía oficial: las fechas de las ramas aún activas son planificadas y pueden ajustarse, solo las de 3.9 y 3.10 están cerradas. Vuelva a leer la página antes de fijar su calendario.

Saber qué intérprete sirve realmente la producción

python3 --version en su shell no dice qué intérprete sirve la aplicación. El servicio puede arrancar un entorno virtual creado hace años, un Python compilado a mano o una imagen congelada en un FROM python:3.10.

Inventaríe cada fuente: la línea ExecStart de la unidad systemd (systemctl cat miapp), el resultado de /srv/miapp/venv/bin/python --version, un grep -rn "FROM python" . sobre sus Dockerfiles, el campo requires-python de pyproject.toml y la versión que usa su CI. Anote también los workers y las tareas programadas: suelen tener su propio entorno y se quedan con el intérprete antiguo mucho después del sitio.

Requisitos antes de empezar

Esta migración no exige una máquina especial, pero sí acceso completo al servidor y sitio para dos entornos en paralelo: el segundo ocupa tanto disco como el primero, más una caché de compilación si alguna dependencia no tiene paquete precompilado.

Necesita un archivo de dependencias bloqueado con versiones exactas, una suite de pruebas ejecutable fuera de producción, una copia reciente de la base de datos y acceso root para instalar, si sus dependencias compiladas lo exigen, un compilador y las cabeceras de desarrollo. Una primera pasada en un VPS de pruebas, aunque sea efímero, vale más que un ensayo en el servidor de producción.

Migrar sin interrumpir el servicio

  1. Congelar lo existente

    Desde el entorno actual, exporte las versiones exactas: /srv/miapp/venv/bin/pip freeze > requirements.lock.txt. Este archivo describe con precisión lo que funciona hoy; es su punto de retorno. Versiónelo antes de continuar.

  2. Instalar Python 3.12 sin tocar el sistema

    uv python install 3.12 descarga un intérprete 3.12 gestionado por uv, sin sustituir el python3 de la distribución, del que dependen sus propias herramientas. Si prefiere los paquetes de su distribución, instale la rama 3.12 desde un repositorio que la ofrezca y use python3.12 -m venv.

  3. Crear el segundo entorno junto al primero

    uv venv --python 3.12 /srv/miapp/venv312 crea el entorno nuevo; sin uv, python3.12 -m venv /srv/miapp/venv312 hace el mismo trabajo. El antiguo sigue sirviendo el tráfico: nada se modifica. Un entorno virtual no se mueve, por eso el nuevo lleva otro nombre.

  4. Reinstalar desde el archivo bloqueado

    VIRTUAL_ENV=/srv/miapp/venv312 uv pip sync requirements.lock.txt instala exactamente las versiones listadas. Con pip: /srv/miapp/venv312/bin/pip install -r requirements.lock.txt. Si una versión fijada no existe para 3.12 o se niega a compilar, la instalación se detiene aquí: es el objetivo, descubre la rotura antes de producción. Anote cada paquete que haya que subir.

  5. Volver a ejecutar la suite de pruebas

    Lance las pruebas con el intérprete nuevo: /srv/miapp/venv312/bin/python -m pytest, o /srv/miapp/venv312/bin/python manage.py test para Django, precedido de manage.py check. Lea el resumen de advertencias de obsolescencia: anuncian las roturas de la versión siguiente. Las pruebas deben pasar con los dos intérpretes antes de continuar.

  6. Subir solo lo que se rompió

    Liste los paquetes implicados, súbalos uno a uno y regenere el archivo bloqueado desde el entorno nuevo: /srv/miapp/venv312/bin/pip freeze > requirements.312.txt. Conserve las dos listas, una por intérprete, mientras dure el cambio.

  7. Arrancar la aplicación en paralelo en un puerto local

    Lánzela con el entorno nuevo en un puerto libre, por ejemplo /srv/miapp/venv312/bin/gunicorn miapp.wsgi --bind 127.0.0.1:8001 (o uvicorn para FastAPI). Envíele peticiones reales con curl: página de inicio, inicio de sesión, una escritura en base de datos. El tráfico público sigue en el proceso antiguo; solo un resultado idéntico justifica pasar al cambio.

Cambiar y volver atrás en una línea

El cambio debe modificar una sola ruta. Haga que la unidad systemd apunte a un enlace en lugar de al propio entorno: ExecStart=/srv/miapp/venv-activo/bin/gunicorn miapp.wsgi --bind 127.0.0.1:8000. Cree primero el enlace al estado actual con ln -sfn /srv/miapp/venv /srv/miapp/venv-activo, luego systemctl daemon-reload y un reinicio que no cambia nada.

El cambio a 3.12 pasa a ser ln -sfn /srv/miapp/venv312 /srv/miapp/venv-activo && systemctl restart miapp, y la vuelta atrás es la misma línea con la ruta antigua. Para una aplicación en contenedor, la palanca es la imagen base: pase de FROM python:3.10-slim a FROM python:3.12-slim, reconstruya con docker compose up -d --build y vuelva atrás restableciendo la línea anterior.

En ambos casos, conserve el entorno o la imagen antiguos unos días y siga los registros con journalctl -u miapp -f durante la primera hora.

Los puntos de rotura que hay que revisar

Entre 3.10 y 3.12, la rotura rara vez viene de su código y casi siempre de lo que lo rodea. Vuelven tres familias: los módulos retirados de la biblioteca estándar, las dependencias compiladas y la versión mínima de sus frameworks. Las notas de versión de Python 3.12 listan lo que desaparece; léalas con su archivo bloqueado abierto al lado.

Lista de control antes del cambio

  • Módulos retirados — Python 3.12 elimina distutils, asynchat, asyncore e imp; grep -rnE "distutils|asyncore|asynchat|import imp" . localiza sus usos directos, la lista de dependencias revela los indirectos.
  • setuptools ya no viene preinstalado — los entornos creados con venv ya no lo incluyen en 3.12; un paquete que importa pkg_resources sin declararlo falla hasta que ejecute pip install setuptools.
  • Paquetes precompilados — las dependencias compiladas (controladores de base de datos, tratamiento de imagen, criptografía) deben publicar un paquete para 3.12; pip install --only-binary=:all: -r requirements.lock.txt falla rápido en lugar de lanzar una compilación.
  • Versiones mínimas de los frameworks — Django 4.2 solo admite Python 3.12 a partir de la 4.2.8, y Django 5.0 y las siguientes lo aceptan; para FastAPI, relea los classifiers de Python de la versión exacta que fije.
  • Advertencias de obsolescencia — datetime.utcnow() y datetime.utcfromtimestamp() están obsoletas en 3.12; sustitúyalas por datetime.now(datetime.UTC) y datetime.fromtimestamp(ts, datetime.UTC).
  • Bibliotecas del sistema compartidas — el entorno paralelo aísla los paquetes de Python, no las bibliotecas del sistema operativo (el cliente de PostgreSQL, por ejemplo): anótelas, una actualización del sistema puede cambiarlas bajo sus pies.

Solución de problemas: los errores que se repiten

Estos mensajes aparecen desde la primera ejecución de las pruebas con Python 3.12. Cada uno tiene una causa conocida y un remedio corto.

Mensaje observado y remedio

  • ModuleNotFoundError: No module named 'distutils' — el módulo salió de la biblioteca estándar. Instale setuptools en el entorno, que sigue ofreciendo una versión, y luego suba la dependencia culpable.
  • ModuleNotFoundError: No module named 'imp' — imp está retirado y importlib lo sustituye. Si la importación viene de un paquete de terceros, suba ese paquete a una versión que ya no lo use.
  • ModuleNotFoundError: No module named 'pkg_resources' — setuptools ya no se instala de oficio en los entornos venv de 3.12. pip install setuptools restablece el módulo hasta que el paquete culpable prescinda de él.
  • DeprecationWarning: datetime.datetime.utcnow() is deprecated — no es un error sino una señal: sustituya la llamada por un objeto con zona horaria.
  • Failed building wheel for <paquete> — este paquete no tiene versión precompilada para 3.12 y pip intenta compilarlo. Súbalo, o instale compilador y cabeceras de desarrollo si no es posible subirlo.

Fijar el destino, no solo migrar

Aproveche la migración para fijar el intérprete en lugar de padecerlo: requires-python = ">=3.12" en pyproject.toml, una etiqueta de imagen precisa en lugar de python:3 y la versión de Python en la matriz de su CI. Añada 3.13 a esa matriz como simple observación: sabrá de antemano si la próxima subida será sencilla.

Hacer de la subida de versión un gesto habitual

Una rama de Python llega al fin de vida cada año, en octubre. El método descrito aquí (entorno paralelo, archivo bloqueado, pruebas, cambio reversible) no depende de ninguna versión concreta: se repite tal cual para 3.11 en octubre de 2027 y para 3.12 en octubre de 2028, según el calendario actual.

Si su aplicación aún no está en un servidor cuyo intérprete controle, nuestra guía de despliegue de Django en un VPS cubre el primer despliegue. Las guías sobre el fin de vida de Node.js y de PHP siguen la misma lógica para los demás runtimes de un parque.

Un servidor donde probar la versión siguiente antes de cambiar

Un VPS con acceso root permite montar un segundo entorno de Python junto al primero, validar las pruebas y después cambiar. La elección del sistema operativo es libre y la capacidad crece en vertical; la opción de administración del VPS toma el relevo si no quiere llevar el servidor usted mismo.

¿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