[{"data":1,"prerenderedAt":203},["ShallowReactive",2],{"seo-verification":3,"blog-python-3-10-end-of-life-migrate-vps-applications-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-python-3-10-end-of-life-migrate-vps-applications-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":30,"intro":33,"sections":34,"ctaTitle":147,"ctaBody":148,"ctaButton":149,"ctaUrl":150,"relatedPosts":151},558,"python-3-10-end-of-life-migrate-vps-applications",{"fr":12,"en":10,"ar":13,"es":14},"python-3-10-fin-de-vie-migrer-applications-vps","نهاية-دعم-python-3-10-ترقية-تطبيقات-vps","python-3-10-fin-de-vida-migrar-aplicaciones-vps","Python 3.10 end of life: migrating your apps on a VPS","Python 3.10 reached end of life in October 2026. Move your apps to 3.12 on a VPS: parallel venv, tests, switchover and a one-line rollback.",9,0,false,"2026-11-01T00:00:00+00:00","2026-11-01T14:14:31+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fpython-3-10-fin-de-vie-migrer-applications-vps-poster.svg","Python 3.10 reached end of life in October 2026: no more security fixes are published for this branch. Your Django or FastAPI application still answers, though, and nothing tells you the interpreter is frozen. The risk builds up silently, and the migration looks heavier with every month of delay. Here is a method that leaves the existing setup untouched: a second Python 3.12 environment next to the first, locked and tested dependencies, then a switchover you can undo in one line.",[35,39,48,80,83,86,89,114,117,120,129,132,140,144],{"type":36,"title":37,"body":38},"h2","What the end of life of Python 3.10 changes","The Python developer's guide publishes the schedule of every branch. Python 3.10, released in October 2021, is listed there as end of life since October 1, 2026. In practice the branch no longer receives any fix, not even security ones: a flaw found in the interpreter or its standard library will stay open.\n\nYour code keeps running and your tests keep passing, which is what makes the situation misleading. End of life breaks nothing on the day itself. It removes the safety net for every following day, while distributions, base images and third-party libraries gradually lose interest.",{"type":40,"title":41,"items":42},"ul","What a frozen interpreter costs",[43,44,45,46,47],"**Unfixed flaws** — any interpreter vulnerability published after end of life stays open on the 3.10 branch; only a version upgrade closes it.","**Dependencies drifting away** — libraries sooner or later raise their minimum Python version; a fresh install ends up resolving old versions, or failing.","**Frozen base images** — a container image built on the 3.10 branch relies on an interpreter with no upstream fixes, and your vulnerability scans flag it on every build.","**Stalled audits** — an unsupported interpreter is a red line in your clients' security reviews and vendor questionnaires.","**Forced migration** — from 3.10 to 3.12 the gap spans two minor versions; the longer you wait, the longer the list of breakages, and a planned project costs less than an emergency after an incident.",{"type":49,"title":50,"headers":51,"rows":55},"comparison","Python branch support calendar",[52,53,54],"Version","End of support","What it means for your VPS",[56,60,64,68,72,76],[57,58,59],"3.9","October 2025","Unsupported for over a year: leave without waiting",[61,62,63],"3.10","October 2026","Unsupported since October 1: no more fixes",[65,66,67],"3.11","October 2027","Minimum step: it fixes today's problem, not next year's",[69,70,71],"3.12","October 2028","Recommended target: two years of margin and an established ecosystem",[73,74,75],"3.13","October 2029","Supported even longer; adopt it once your dependencies are validated",[77,78,79],"3.14","October 2030","Newest branch in this table, with the furthest end of support",{"type":36,"title":81,"body":82},"Which target version to choose","Python 3.12 is the target we recommend for an existing application: its end of support is scheduled for October 2028, two years of margin, and mainstream frameworks support it. Python 3.11 is a minimum step that puts you back in front of the same migration in October 2027.\n\nPython 3.13 is supported even longer, until October 2029. We do not consider it unsuitable: it only assumes that each of your dependencies publishes packages for that version, which you can check in your test environment. A reminder from the official guide: the dates of branches that are still active are scheduled and can be adjusted, only those of 3.9 and 3.10 are settled. Reread the page before fixing your calendar.",{"type":36,"title":84,"body":85},"Knowing which interpreter really serves production","`python3 --version` in your shell does not tell you which interpreter serves the application. The service may start a virtual environment created years ago, a hand-compiled Python, or an image frozen in a `FROM python:3.10`.\n\nList every source: the `ExecStart` line of the systemd unit (`systemctl cat myapp`), the output of `\u002Fsrv\u002Fmyapp\u002Fvenv\u002Fbin\u002Fpython --version`, a `grep -rn \"FROM python\" .` over your Dockerfiles, the `requires-python` field of `pyproject.toml` and the version used by your CI. Also note workers and scheduled jobs: they often have their own environment and stay on the old interpreter long after the website.",{"type":36,"title":87,"body":88},"Prerequisites before you start","This migration needs no special machine, but it needs full access to the server and room for two environments side by side: the second takes as much disk as the first, plus a build cache if a dependency has no precompiled package.\n\nYou need a locked dependency file with exact versions, a test suite you can run outside production, a recent database backup and root access to install, if your compiled dependencies require it, a compiler and the development headers. A first pass on a test VPS, even a short-lived one, beats a trial on the production server.",{"type":90,"title":91,"steps":92},"steps","Migrating without interrupting the service",[93,96,99,102,105,108,111],{"title":94,"body":95},"Freeze what exists","From the current environment, export the exact versions: `\u002Fsrv\u002Fmyapp\u002Fvenv\u002Fbin\u002Fpip freeze > requirements.lock.txt`. This file describes precisely what runs today; it is your way back. Commit it before going further.",{"title":97,"body":98},"Install Python 3.12 without touching the system","`uv python install 3.12` downloads a 3.12 interpreter managed by uv, without replacing the distribution's `python3` that its own tools depend on. If you prefer your distribution's packages, install the 3.12 branch from a repository that provides it and use `python3.12 -m venv`.",{"title":100,"body":101},"Create the second environment next to the first","`uv venv --python 3.12 \u002Fsrv\u002Fmyapp\u002Fvenv312` creates the new environment; without uv, `python3.12 -m venv \u002Fsrv\u002Fmyapp\u002Fvenv312` does the same job. The old one keeps serving traffic: nothing is modified. A virtual environment cannot be moved, which is why the new one has a different name.",{"title":103,"body":104},"Reinstall from the locked file","`VIRTUAL_ENV=\u002Fsrv\u002Fmyapp\u002Fvenv312 uv pip sync requirements.lock.txt` installs exactly the listed versions. With pip: `\u002Fsrv\u002Fmyapp\u002Fvenv312\u002Fbin\u002Fpip install -r requirements.lock.txt`. If a pinned version does not exist for 3.12 or refuses to build, the installation stops here: that is the point, you find the breakage before production. Note every package to upgrade.",{"title":106,"body":107},"Replay the test suite","Run the tests with the new interpreter: `\u002Fsrv\u002Fmyapp\u002Fvenv312\u002Fbin\u002Fpython -m pytest`, or `\u002Fsrv\u002Fmyapp\u002Fvenv312\u002Fbin\u002Fpython manage.py test` for Django, preceded by `manage.py check`. Read the summary of deprecation warnings: they announce the breakages of the next version. Tests must pass with both interpreters before you continue.",{"title":109,"body":110},"Upgrade only what broke","List the packages at fault, upgrade them one by one, then regenerate the locked file from the new environment: `\u002Fsrv\u002Fmyapp\u002Fvenv312\u002Fbin\u002Fpip freeze > requirements.312.txt`. Keep both lists, one per interpreter, for the duration of the switchover.",{"title":112,"body":113},"Start the application in parallel on a local port","Run it with the new environment on a free port, for example `\u002Fsrv\u002Fmyapp\u002Fvenv312\u002Fbin\u002Fgunicorn myapp.wsgi --bind 127.0.0.1:8001` (or `uvicorn` for FastAPI). Send it real requests with `curl`: home page, login, a database write. Public traffic stays on the old process; only an identical result justifies moving to the switchover.",{"type":36,"title":115,"body":116},"Switching over and rolling back in one line","The switchover must change a single path. Point the systemd unit at a link rather than at the environment itself: `ExecStart=\u002Fsrv\u002Fmyapp\u002Fvenv-active\u002Fbin\u002Fgunicorn myapp.wsgi --bind 127.0.0.1:8000`. First create the link to the current state with `ln -sfn \u002Fsrv\u002Fmyapp\u002Fvenv \u002Fsrv\u002Fmyapp\u002Fvenv-active`, then `systemctl daemon-reload` and a restart that changes nothing.\n\nThe switch to 3.12 then becomes `ln -sfn \u002Fsrv\u002Fmyapp\u002Fvenv312 \u002Fsrv\u002Fmyapp\u002Fvenv-active && systemctl restart myapp`, and the rollback is the same line with the old path. For a containerized application, the lever is the base image: change `FROM python:3.10-slim` to `FROM python:3.12-slim`, rebuild with `docker compose up -d --build` and roll back by restoring the previous line.\n\nIn both cases, keep the old environment or image for a few days, and follow the logs with `journalctl -u myapp -f` during the first hour.",{"type":36,"title":118,"body":119},"Breakage points to check","Between 3.10 and 3.12, breakage rarely comes from your code and almost always from what surrounds it. Three families come back: modules removed from the standard library, compiled dependencies and the minimum version of your frameworks. The Python 3.12 release notes list what disappears; read them with your locked file open next to them.",{"type":40,"title":121,"items":122},"Checklist before the switchover",[123,124,125,126,127,128],"**Removed modules** — Python 3.12 removes `distutils`, `asynchat`, `asyncore` and `imp`; `grep -rnE \"distutils|asyncore|asynchat|import imp\" .` finds your direct uses, the list of your dependencies reveals the indirect ones.","**setuptools is no longer preinstalled** — environments created by `venv` no longer ship it in 3.12; a package that imports `pkg_resources` without declaring it fails until you run `pip install setuptools`.","**Precompiled packages** — compiled dependencies (database drivers, image processing, cryptography) must publish a package for 3.12; `pip install --only-binary=:all: -r requirements.lock.txt` fails fast instead of starting a build.","**Minimum framework versions** — Django 4.2 supports Python 3.12 only from 4.2.8, and Django 5.0 and later accept it; for FastAPI, reread the Python classifiers of the exact version you pin.","**Deprecation warnings** — `datetime.utcnow()` and `datetime.utcfromtimestamp()` are deprecated in 3.12; replace them with `datetime.now(datetime.UTC)` and `datetime.fromtimestamp(ts, datetime.UTC)`.","**Shared system libraries** — the parallel environment isolates Python packages, not the OS libraries (the PostgreSQL client, for example): note them, a system update can change them under your feet.",{"type":36,"title":130,"body":131},"Troubleshooting: the errors that keep coming back","These messages appear as soon as the tests first run under Python 3.12. Each has a known cause and a short remedy.",{"type":40,"title":133,"items":134},"Observed message and remedy",[135,136,137,138,139],"**ModuleNotFoundError: No module named 'distutils'** — the module left the standard library. Install `setuptools` in the environment, which still provides a version of it, then upgrade the faulty dependency.","**ModuleNotFoundError: No module named 'imp'** — `imp` is removed, `importlib` replaces it. If the import comes from a third-party package, upgrade that package to a version that no longer uses it.","**ModuleNotFoundError: No module named 'pkg_resources'** — setuptools is no longer installed by default in 3.12 venv environments. `pip install setuptools` restores the module until the faulty package stops needing it.","**DeprecationWarning: datetime.datetime.utcnow() is deprecated** — not an error but a signal: replace the call with a timezone-aware object.","**Failed building wheel for \u003Cpackage>** — this package has no precompiled version for 3.12 and pip tries to build it. Upgrade it, or install a compiler and development headers if upgrading is impossible.",{"type":141,"title":142,"body":143},"tip","Pin the target, do not just migrate","Use the migration to fix the interpreter instead of enduring it: `requires-python = \">=3.12\"` in `pyproject.toml`, a precise image tag rather than `python:3`, and the Python version in your CI matrix. Add 3.13 to that matrix as a mere observation: you will know in advance whether the next upgrade will be simple.",{"type":36,"title":145,"body":146},"Making version upgrades a routine","A Python branch reaches end of life every year, in October. The method described here (parallel environment, locked file, tests, reversible switchover) depends on no specific version: it replays as is for 3.11 in October 2027 and for 3.12 in October 2028, according to the current calendar.\n\nIf your application is not yet on a server whose interpreter you control, our guide to deploying Django on a VPS covers the first deployment. The guides on the end of life of Node.js and PHP follow the same logic for the other runtimes of a fleet.","A server to test the next version before switching over","A VPS with root access lets you build a second Python environment next to the first, validate the tests, then switch over. The choice of OS is free and capacity scales vertically; the VPS administration option takes over if you do not want to run the server yourself.","Compare VPS plans","\u002Fvps-cloud",[152,169,185],{"id":153,"slug":154,"slugs":155,"title":159,"excerpt":160,"readTime":161,"views":162,"isPinned":19,"publishedAt":163,"updatedAt":164,"category":165,"categories":166,"featuredImage":30,"bgImage":31,"posterImage":168,"relatedSolution":30},223,"nodejs-20-end-of-life-migrating-your-vps",{"fr":156,"en":154,"ar":157,"es":158},"nodejs-20-fin-de-vie-migrer-vps","نهاية-دعم-nodejs-20-ترحيل-خادم-vps","nodejs-20-fin-de-vida-migrar-vps","Node.js 20 end of life: migrating your VPS","Node.js 20 has had no security patch since April 30, 2026. How to audit your servers and migrate to Node.js 24 without breaking production.",5,2,"2026-08-05T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[167],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fnodejs-20-fin-de-vie-migrer-vps-poster.svg",{"id":170,"slug":171,"slugs":172,"title":176,"excerpt":177,"readTime":178,"views":179,"isPinned":19,"publishedAt":180,"updatedAt":164,"category":181,"categories":182,"featuredImage":30,"bgImage":31,"posterImage":184,"relatedSolution":30},206,"php-82-end-of-life-planning-your-migration",{"fr":173,"en":171,"ar":174,"es":175},"php-82-fin-de-vie-checklist-migration","نهاية-دعم-php-82-دليل-الترحيل","php-82-fin-de-vida-planificar-la-migracion","PHP 8.2 end of life: your migration checklist","PHP 8.2 reaches EOL on December 31, 2026. Inventory your stack, compare PHP versions, and follow a step-by-step migration checklist to PHP 8.3 or 8.4.",11,7,"2026-08-01T00:00:00+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[183],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fphp-82-fin-de-vie-checklist-migration-poster.svg",{"id":186,"slug":187,"slugs":188,"title":192,"excerpt":193,"readTime":194,"views":179,"isPinned":19,"publishedAt":195,"updatedAt":164,"category":196,"categories":197,"featuredImage":30,"bgImage":31,"posterImage":199,"relatedSolution":200},44,"deploy-a-django-application-on-a-vps",{"fr":189,"en":187,"ar":190,"es":191},"deployer-django-vps","نشر-تطبيق-django-على-vps","desplegar-una-aplicacion-django-en-un-vps","Deploy a Django Application on a VPS","Deploy Django on a VPS: Gunicorn, Nginx, PostgreSQL, Docker, and SSL. A complete guide for Python developers who want to self-host.",3,"2026-05-07T00:00:00+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[198],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-django-vps-poster.svg",{"categorySlug":201,"appSlug":202},"development","django",1793543010503]