Установка Python 3.12 на Debian 13, 12 и 11

⚠️ Важное предупреждение: Python 3.12 находится в режиме только исправления безопасности (source-only security fixes). Обычные багфиксы и новые возможности закончились с версией 3.12.10. Если вы начинаете новый проект — используйте Python 3.13 или 3.14. Эта инструкция — для поддержки существующего кода.

Оглавление

Предварительные требования

Прежде чем начать, убедитесь, что ваша система готова:

⚠️ ВАЖНО: Проверьте права sudo перед установкой

Если вы не уверены, есть ли у вашего пользователя права администратора, выполните в терминале:

sudo whoami

Что делает:

  • sudo — выполняет команду от имени суперпользователя
  • whoami — показывает имя текущего пользователя

Зачем: Проверяет, может ли ваш пользователь выполнять команды с правами root.

✅ Если выводит root — всё в порядке, можете продолжать.

❌ Если выводит is not in the sudoers file — сначала пройдите наше руководство по настройке sudo.

Дополнительные требования:

  • Не менее 2-3 ГБ свободного места (исходники, сборка, установка)
  • Интернет-соединение для скачивания исходников
  • Debian 13, 12 или 11 (любая архитектура, поддерживаемая Debian)

Почему нет пакета python3.12 в Debian?

Debian 13, 12 и 11 не содержат пакет python3.12 в своих стандартных репозиториях. Это связано с тем, что:

  • Debian 13 (Trixie) поставляется с Python 3.13
  • Debian 12 (Bookworm) поставляется с Python 3.11
  • Debian 11 (Bullseye) поставляется с Python 3.9

А Python 3.12 находится в «промежуточном» положении — он уже не новый, но и не старый настолько, чтобы быть в stable-репозиториях.

ВариантСтатусКогда использовать
Сборка из исходниковРаботает на всех версиях DebianЕдинственный безопасный способ
— нужен Python 3.12
APT-пакет из testing/unstableНе для stable-системНе используйте — сломает систему
Ubuntu PPAНе совместим с DebianНикогда

Что нужно знать перед установкой (правила безопасности)

Чтобы не повредить Debian, соблюдайте эти правила:

ПравилоПочему это важно
Запускайте Python командой python3.12Системный python3 принадлежит Debian —
не трогайте его
Используйте виртуальные окружения (venv)pip не будет писать в системные директории Debian
Сборка использует make altinstallУстанавливает в /usr/local/python3.12, а не поверх
системного
Не создавайте update-alternatives для python3Это заменит системный интерпретатор и сломает ОС
Не удаляйте системный PythonБез него перестанут работать APT и половина утилит

Проверка вашей версии Debian

. /etc/os-release
printf '%s\n' "$PRETTY_NAME"

Что делает: Показывает точное название вашей версии Debian.

python3 --version

Что делает: Показывает версию системного Python.

python3.12 --version 2>/dev/null || echo "Python 3.12 не установлен"

Что делает: Проверяет, не установлен ли уже Python 3.12.

Ожидаемые выводы:

Debian 13 (Trixie)Debian 12 (Bookworm)Debian 11 (Bullseye)
Debian GNU/Linux 13 (trixie)Debian GNU/Linux 12 (bookworm)Debian GNU/Linux 11 (bullseye)
Python 3.13.5Python 3.11.2Python 3.9.2
Python 3.12 не установленPython 3.12 не установленPython 3.12 не установлен

Примечание: В таблице «Ожидаемые выводы» для Debian 13 указано Python 3.13.5, но в будущем версия может измениться

Подготовка Debian к сборке Python 3.12

Шаг 1: Обновление системы

sudo apt update

Что делает: Обновляет список доступных пакетов.

Зачем: Всегда обновляйте список пакетов перед установкой нового ПО.

Шаг 2: Установка инструментов сборки и зависимостей

sudo apt install -y ca-certificates wget python3 build-essential zlib1g-dev libncurses-dev \
libgdbm-dev libgdbm-compat-dev libnss3-dev libssl-dev libsqlite3-dev libreadline-dev \
libffi-dev libbz2-dev liblzma-dev uuid-dev libexpat1-dev tk-dev pkg-config make libdb-dev

Что делает: Устанавливает компилятор gcc, заголовочные файлы и библиотеки, необходимые для сборки Python со всеми модулями (SSL, SQLite, сжатие, readline, Tkinter и другие).

Зачем: Без этих пакетов Python соберётся с минимальной функциональностью — многие важные модули (ssl, sqlite3, tkinter) будут отсутствовать.

Шаг 3: Проверка свободного места

df -h "$HOME" /usr/local

Что делает: Показывает свободное место в домашней директории и /usr/local.

Зачем: Сборка требует несколько гигабайт свободного места (~2-3 ГБ).

Создание скрипта-помощника для сборки

Вместо выполнения десятка команд вручную, мы создадим скрипт, который автоматически:

  1. Найдёт последнюю версию Python 3.12 на python.org (с учётом режима security-fix)
  2. Скачает исходники и проверит их SHA-256 контрольную сумму
  3. Соберёт Python с оптимальными настройками
  4. Установит его в /usr/local/python3.12 через make altinstall
  5. Создаст символическую ссылку /usr/local/bin/python3.12 (только если не конфликтует)

Создание файла скрипта

cat <<'EOF' > install-python312-source-debian.sh
#!/usr/bin/env bash
# UnishellRu Python 3.12 source helper
set -euo pipefail

INSTALL_PREFIX="${INSTALL_PREFIX:-/usr/local/python3.12}"
BUILD_DIR="${BUILD_DIR:-$HOME/python3.12-source-build}"
PY312_COMMAND_NAME="${PY312_COMMAND_NAME:-python3.12}"
PY312_BIN="$INSTALL_PREFIX/bin/python3.12"
PY312_FORCE_REBUILD="${PY312_FORCE_REBUILD:-0}"

validate_settings() {
    if [[ -z "$INSTALL_PREFIX" || "$INSTALL_PREFIX" != /* ]]; then
        printf 'INSTALL_PREFIX must be an absolute path.\n' >&2
        exit 1
    fi

    if [[ -z "$PY312_COMMAND_NAME" || "$PY312_COMMAND_NAME" == */* || "$PY312_COMMAND_NAME" =~ [[:space:]] ]]; then
        printf 'PY312_COMMAND_NAME must be a command name, not a path or a value with spaces.\n' >&2
        exit 1
    fi
}

require_cmd() {
    if ! command -v "$1" >/dev/null 2>&1; then
        printf 'Missing required command: %s\n' "$1" >&2
        exit 1
    fi
}

validate_settings

for cmd in python3 awk; do
    require_cmd "$cmd"
done

mkdir -p "$BUILD_DIR"

require_link_cmds() {
    for cmd in sudo readlink grep mktemp install ln; do
        require_cmd "$cmd"
    done
}

require_build_cmds() {
    for cmd in wget tar make gcc sha256sum nproc tail; do
        require_cmd "$cmd"
    done
    require_link_cmds
}

is_managed_wrapper() {
    local path="$1"
    local target="$2"
    [ -f "$path" ] && grep -Fqx '# UnishellRu Python 3.12 source wrapper' "$path" && grep -Fqx "PY312_SOURCE_TARGET='$target'" "$path"
}

write_command_wrapper() {
    local target="$1"
    local link="$2"
    local tmp_file=""

    tmp_file="$(mktemp)"
    {
        printf '%s\n' '#!/usr/bin/env sh'
        printf '%s\n' '# UnishellRu Python 3.12 source wrapper'
        printf "PY312_SOURCE_TARGET='%s'\n" "$target"
        # shellcheck disable=SC2016
        printf '%s\n' 'exec "$PY312_SOURCE_TARGET" "$@"'
    } >"$tmp_file"
    sudo install -m 0755 "$tmp_file" "$link"
    rm -f "$tmp_file"
}

check_command_target_safe() {
    local target="$1"
    local link="/usr/local/bin/$PY312_COMMAND_NAME"
    local existing_path=""
    local existing_target=""

    if existing_path="$(command -v "$PY312_COMMAND_NAME" 2>/dev/null)"; then
        existing_target="$(readlink -f "$existing_path" 2>/dev/null || true)"
        if [ -n "$existing_target" ] && [ "$existing_target" != "$target" ] && ! is_managed_wrapper "$existing_path" "$target"; then
            printf 'Refusing to shadow existing %s at %s\n' "$PY312_COMMAND_NAME" "$existing_path" >&2
            printf 'Set PY312_COMMAND_NAME to a separate name, such as python3.12-source, when another package owns the command.\n' >&2
            exit 1
        fi
    fi

    if [ -e "$link" ] && [ ! -L "$link" ] && ! is_managed_wrapper "$link" "$target"; then
        printf 'Refusing to overwrite unmanaged path: %s\n' "$link" >&2
        exit 1
    fi

    if [ -L "$link" ]; then
        existing_target="$(readlink -f "$link" 2>/dev/null || true)"
        if [ -n "$existing_target" ] && [ "$existing_target" != "$target" ]; then
            printf 'Refusing to retarget existing symlink: %s\n' "$link" >&2
            exit 1
        fi
    fi
}

install_command_link() {
    local target="$1"
    local link="/usr/local/bin/$PY312_COMMAND_NAME"

    check_command_target_safe "$target"

    if [ "$PY312_COMMAND_NAME" = "python3.12" ]; then
        sudo ln -sfn "$target" "$link"
    else
        write_command_wrapper "$target" "$link"
    fi
}

fetch_release_metadata() {
    python3 - <<'PY'
import gzip
import re
from urllib.request import urlopen

release_html = urlopen("https://www.python.org/downloads/latest/python3.12/", timeout=20).read()
if release_html.startswith(b"\x1f\x8b"):
    release_html = gzip.decompress(release_html)
release_html = release_html.decode("utf-8")

version_match = re.search(r'<h1 class="page-title">Python (3\.12\.\d+)</h1>', release_html)
if not version_match:
    raise SystemExit("Could not find the latest Python 3.12 release version")
version = version_match.group(1)

row = re.search(
    r'<tr>\s*<td><a href="(?P<url>[^"]*Python-' + re.escape(version) + r'\.tar\.xz)">XZ compressed source tarball</a></td>.*?<code class="checksum">(?P<checksum>.*?)</code>',
    release_html,
    re.S,
)
if not row:
    raise SystemExit("Could not find the XZ source tarball checksum")

checksum_text = re.sub(r"<[^>]+>", "", row.group("checksum"))
sha256 = re.sub(r"[^0-9a-f]", "", checksum_text)
if len(sha256) != 64:
    raise SystemExit(f"Unexpected SHA-256 checksum length: {len(sha256)}")

print(f"PY312_VERSION='{version}'")
print(f"PY312_URL='{row.group('url')}'")
print(f"PY312_SHA256='{sha256}'")
PY
}

run_logged() {
    local label="$1"
    shift
    local log_file="$BUILD_DIR/${label}-${PY312_VERSION}.log"
    if "$@" >"$log_file" 2>&1; then
        printf '%s complete; see %s\n' "$label" "${label}-${PY312_VERSION}.log"
    else
        printf '%s failed; last log lines:\n' "$label" >&2
        tail -n 50 "$log_file" >&2 || true
        exit 1
    fi
}

metadata_file="$BUILD_DIR/python312-release.env"
fetch_release_metadata >"$metadata_file"
# shellcheck source=/dev/null
. "$metadata_file"

printf 'Using Python %s\n' "$PY312_VERSION"

if [ -x "$PY312_BIN" ]; then
    current_version="$("$PY312_BIN" --version | awk '{print $2}')"
    if [ "$current_version" = "$PY312_VERSION" ] && [ "$PY312_FORCE_REBUILD" != "1" ]; then
        require_link_cmds
        install_command_link "$PY312_BIN"
        printf 'Python %s already installed at %s\n' "$current_version" "$PY312_BIN"
        exit 0
    fi
fi

require_build_cmds
check_command_target_safe "$PY312_BIN"

cd "$BUILD_DIR"
archive="Python-${PY312_VERSION}.tar.xz"
srcdir="Python-${PY312_VERSION}"

sudo rm -rf -- "$srcdir"
rm -f -- "$archive"
wget -q -O "$archive" "$PY312_URL"
printf '%s  %s\n' "$PY312_SHA256" "$archive" | sha256sum -c -
tar -xf "$archive"

cd "$srcdir"
configure_args=(--with-ensurepip=install "--prefix=$INSTALL_PREFIX")
if [ -n "${PY312_CONFIGURE_EXTRA:-}" ]; then
    # shellcheck disable=SC2206
    extra_args=($PY312_CONFIGURE_EXTRA)
    configure_args+=("${extra_args[@]}")
fi

run_logged configure ./configure "${configure_args[@]}"
run_logged make make -j"$(nproc)"
run_logged altinstall sudo make altinstall

printf '%s\n' "$INSTALL_PREFIX/lib" | sudo tee "/etc/ld.so.conf.d/${PY312_COMMAND_NAME}.conf" >/dev/null
sudo ldconfig

if [ -x "$PY312_BIN" ]; then
    install_command_link "$PY312_BIN"
    "$PY312_BIN" --version
    cd "$BUILD_DIR"
    sudo rm -rf -- "$srcdir"
    rm -f -- "$archive"
else
    printf 'Build completed, but %s was not found.\n' "$PY312_BIN" >&2
    exit 1
fi
EOF

Что делает этот скрипт (обзорно):

  • Проверяет наличие всех необходимых команд
  • Скачивает с python.org страницу последнего релиза Python 3.12 и SHA-256 контрольную сумму
  • Скачивает исходники и проверяет их целостность
  • Конфигурирует сборку с поддержкой всех модулей
  • Собирает Python, используя все ядра процессора (-j"$(nproc)")
  • Устанавливает через make altinstall (безопасная установка в отдельный префикс)
  • Создаёт символическую ссылку в /usr/local/bin (с проверкой конфликтов)
chmod +x install-python312-source-debian.sh

Что делает: Делает скрипт исполняемым.

Запуск сборки Python 3.12

./install-python312-source-debian.sh

Что делает: Запускает скрипт сборки.

Ожидаемый вывод:

Using Python 3.12.13
Python-3.12.13.tar.xz: OK
configure complete; see configure-3.12.13.log
make complete; see make-3.12.13.log
altinstall complete; see altinstall-3.12.13.log
Python 3.12.13

Что означают ключевые строки:

  • Using Python 3.12.13 — определена версия для установки
  • Python-3.12.13.tar.xz: OK — контрольная сумма совпала, архив не повреждён
  • Python 3.12.13 — финальный вывод установленного интерпретатора

⚠️ Если видите FAILED или mismatch — не продолжайте. Это означает, что скачанный архив повреждён или подменён.

Сколько это займёт: На современном компьютере сборка занимает 5-15 минут, в зависимости от количества ядер процессора.

Установка скрипта обновления (после успешной сборки)

sudo install -m 0755 install-python312-source-debian.sh /usr/local/bin/update-python312-source

Что делает: Копирует скрипт в /usr/local/bin с правами на исполнение, чтобы можно было обновлять Python одной командой.

command -v update-python312-source

Ожидаемый вывод: /usr/local/bin/update-python312-source

Проверка установки Python 3.12

Проверка версии

python3.12 --version

Ожидаемый вывод: Python 3.12.x (где x — последняя security-версия с python.org).

Проверка важных модулей

python3.12 -c "import ssl, sqlite3, bz2, lzma, zlib, ctypes, readline, tkinter, dbm.gnu; print('Python 3.12 готов на Debian')"

Что делает: Импортирует ключевые модули стандартной библиотеки.

Ожидаемый вывод: Python 3.12 готов на Debian

Если получили ошибку импорта — значит, не установлен соответствующий -dev пакет. Установите недостающий пакет и пересоберите Python (см. раздел «Решение проблем»).

Проверка pip

python3.12 -m pip --version

Что делает: Показывает версию pip, установленного для Python 3.12.

Ожидаемый вывод: pip 25.x from /usr/local/python3.12/lib/python3.12/site-packages/pip (python 3.12)

Использование Python 3.12 через виртуальное окружение

⚠️ Важнейшее правило: Никогда не устанавливайте пакеты через pip глобально для python3.12. Всегда используйте виртуальные окружения (venv).

Создание виртуального окружения

mkdir -p "$HOME/venvs"

Что делает: Создаёт директорию для всех виртуальных окружений (если её нет).

python3.12 -m venv "$HOME/venvs/py312"

Что делает: Создаёт виртуальное окружение с Python 3.12.

Зачем: Внутри venv можно устанавливать любые пакеты через pip без риска повредить систему.

Активация виртуального окружения

source "$HOME/venvs/py312/bin/activate"

Что делает: Активирует виртуальное окружение в текущем сеансе терминала.

Ожидаемое изменение приглашения: (py312) user@debian:~$

Установка пакетов внутри venv

python -m pip install --upgrade pip
python -m pip install requests

Что делает: Обновляет pip в окружении и устанавливает пакет requests.

Зачем: python внутри venv ссылается на Python 3.12, а не на системный.

Проверка, что вы внутри venv

which python

Ожидаемый вывод: /home/username/venvs/py312/bin/python

Деактивация виртуального окружения

deactivate

Что делает: Возвращает терминал к системному Python.

Обновление Python 3.12

Так как Python собран из исходников, он не обновляется через APT. При выходе новой security-версии 3.12.x выполните:

update-python312-source

Что делает: Проверяет последнюю версию на python.org и пересобирает, если нужно.

Если новая версия не требуется, скрипт выведет:

Using Python 3.12.13
Python 3.12.13 already installed at /usr/local/python3.12/bin/python3.12

Принудительная пересборка (если менялись зависимости или флаги):

PY312_FORCE_REBUILD=1 update-python312-source

Удаление Python 3.12

Если Python 3.12 больше не нужен:

⚠️ Перед удалением: Убедитесь, что ни один проект не использует виртуальные окружения с этим Python.

# Удаление символической ссылки
sudo rm -f /usr/local/bin/python3.12

# Удаление скрипта обновления
sudo rm -f /usr/local/bin/update-python312-source

# Удаление самой установки Python
sudo rm -rf /usr/local/python3.12

# Удаление конфигурации динамического линковщика
sudo rm -f /etc/ld.so.conf.d/python3.12.conf
sudo ldconfig

# Удаление директории со сборкой
sudo rm -rf "$HOME/python3.12-source-build"

# Удаление виртуального окружения (если создавали)
rm -rf "$HOME/venvs/py312"

# Очистка кэша команд
hash -r

Проверка удаления:

command -v python3.12 || echo "python3.12 удалён"
python3 --version

Решение типичных проблем

8.1 Ошибка: APT не может найти пакет python3.12

Симптом: sudo apt install python3.12 выдаёт E: Unable to locate package python3.12.

Причина: В Debian 13, 12 и 11 нет пакета python3.12 в официальных репозиториях. Это ожидаемое поведение.

Решение: Используйте сборку из исходников (описанную выше). Не добавляйте testing/unstable или Ubuntu PPA.

8.2 Ошибка: Скрипт отказывается создавать python3.12 (shadow)

Симптом: Скрипт выводит Refusing to shadow existing python3.12 at /usr/bin/python3.12.

Причина: Команда python3.12 уже существует (например, вы установили её из другого источника).

Решение: Используйте side-установку с другим именем:

INSTALL_PREFIX=/usr/local/python3.12-side \
PY312_COMMAND_NAME=python3.12-side \
./install-python312-source-debian.sh

8.3 Ошибка: pip не работает (ModuleNotFoundError)

Симптом: python3.12 -m pip --version выдаёт ModuleNotFoundError: No module named 'pip'.

Причина: Скрипт собирал Python без флага --with-ensurepip=install (но в нашем скрипте он есть).

Решение: Убедитесь, что pip существует:

/usr/local/python3.12/bin/pip3.12 --version

Если нет — пересоберите с флагом:

PY312_FORCE_REBUILD=1 update-python312-source

8.4 Ошибка: Missing modules после сборки (_ssl, _sqlite3 и др.)

Симптом: При импорте модуля (import ssl) получаете ModuleNotFoundError.

Причина: Не был установлен соответствующий -dev пакет до сборки.

Пошаговое решение:

Шаг 1: Установите недостающие заголовочные файлы:

sudo apt install libssl-dev libsqlite3-dev libbz2-dev liblzma-dev tk-dev -y

Шаг 2: Принудительно пересоберите Python:

PY312_FORCE_REBUILD=1 update-python312-source

Шаг 3: Проверьте, что модуль теперь импортируется:

python3.12 -c "import ssl; print('SSL OK')"

8.5 Ошибка: Недостаточно памяти для сборки

Симптом: Процесс сборки прерывается с ошибкой «Cannot allocate memory» или «Killed».

Причина: На сервере меньше 2 ГБ ОЗУ, и процесс компиляции убивает OOM Killer.

Пошаговое решение:

Шаг 1: Проверьте доступную память:

free -h

Шаг 2: Добавьте swap (если нет или мало):

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Шаг 3: Сделайте swap постоянным (добавьте в /etc/fstab):

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

8.6 Ошибка: Debian Tools сломались после изменений Python

Симптом: APT или другие утилиты выдают ошибки, связанные с Python.

Причина: Был заменён или удалён системный /usr/bin/python3.

Пошаговое решение:

Шаг 1: Проверьте, куда указывает системный Python:

ls -l /usr/bin/python3
dpkg -S /usr/bin/python3

Что ищем: Должна быть ссылка на /usr/bin/python3.x (например, /usr/bin/python3.11).

Шаг 2: Переустановите системные пакеты Python:

sudo apt install --reinstall python3 python3-minimal python3-apt -y

Шаг 3: Проверьте:

python3 --version
sudo apt update

Чек-лист: что проверить после установки

  • [ ] sudo whoami выводит root
  • [ ] python3 --version показывает версию системного Python (3.13 на Trixie, 3.11 на Bookworm, 3.9 на Bullseye)
  • [ ] python3.12 --version показывает Python 3.12.x
  • [ ] python3.12 -c "import ssl, sqlite3, bz2, lzma, zlib" выполняется без ошибок
  • [ ] python3.12 -m pip --version показывает pip из /usr/local/python3.12
  • [ ] command -v update-python312-source показывает /usr/local/bin/update-python312-source
  • [ ] Виртуальное окружение создаётся: python3.12 -m venv /tmp/test-venv
  • [ ] Внутри venv работает pip install

Заключение

Python 3.12 успешно установлен на Debian в отдельный префикс /usr/local/python3.12. Системный Python остался нетронутым. Теперь вы можете:

  • Поддерживать легаси-проекты, которые ещё не перешли на Python 3.13 или 3.14
  • Использовать виртуальные окружения для изоляции зависимостей
  • Обновлять Python одной командой update-python312-source при выходе security-исправлений

Что дальше:

💡 Важно: Python 3.12 получает только исправления безопасности. Не ждите новых функций. Если ваш проект позволяет — планируйте переход на Python 3.13 или 3.14. Если нет — эта установка обеспечит безопасную и стабильную среду для вашего легаси-кода.