cheat sheet
Python Installation
Install Python 3 on Debian/Ubuntu, Fedora/RHEL, and Arch Linux. Covers package managers, pyenv, and building from source for unsupported distros.
Python Installation — Linux
Debian / Ubuntu
sudo apt update
sudo apt install python3 python3-pip python3-venv python3-dev -y
Output:
Reading package lists... Done
The following NEW packages will be installed:
python3 python3-dev python3-pip python3-venv
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
For a newer version than the distro default, add the deadsnakes PPA:
sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt update
sudo apt install python3.12 python3.12-venv python3.12-dev -y
Fedora / RHEL / Rocky / AlmaLinux
# Fedora
sudo dnf install python3 python3-pip -y
# RHEL / Rocky / AlmaLinux — enable EPEL first
sudo dnf install epel-release -y
sudo dnf install python3.12 -y
Output:
Installed:
python3.12-3.12.3-1.fc40.x86_64
python3.12-libs-3.12.3-1.fc40.x86_64
Complete!
Arch Linux / Manjaro
sudo pacman -Syu python python-pip
Output:
resolving dependencies...
Packages (2) python-3.12.3-1 python-pip-24.0-1
Total Installed Size: 74.32 MiB
:: Proceed with installation? [Y/n] Y
Arch's
pythonpackage always tracks the latest stable Python, so it updates frequently. This is excellent for getting new versions but can occasionally break packages that haven't updated yet.
pyenv — version-independent approach
Works on any Linux distro. Installs Python in your home directory, no root required.
# Install build dependencies (Debian/Ubuntu)
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \
libffi-dev liblzma-dev
# Install pyenv
curl https://pyenv.run | bash
# Append to ~/.bashrc / ~/.zshrc
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
source ~/.bashrc
# Install and set default
pyenv install 3.12.3
pyenv global 3.12.3
Output:
Downloading Python-3.12.3.tar.xz...
-> https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tar.xz
Installing Python-3.12.3...
Installed Python-3.12.3 to /home/alice/.pyenv/versions/3.12.3
Building from source (unsupported distros)
Use this when no package manager provides your target version:
# Install build dependencies first (Debian/Ubuntu)
sudo apt install -y build-essential libssl-dev zlib1g-dev libffi-dev libsqlite3-dev
# Download and build
wget https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tgz
tar xf Python-3.12.3.tgz
cd Python-3.12.3
./configure --enable-optimizations --with-ensurepip=install
make -j$(nproc)
sudo make altinstall # altinstall avoids overwriting the system python3
Output:
Collecting setuptools
Collecting pip
Installing collected packages: setuptools, pip
Successfully installed pip-24.0 setuptools-69.5.1
Use
make altinstall(notmake install) to avoid replacing the systempython3symlink, which could break OS tools.
Verify
python3 --version
python3 -m pip --version
python3 -c "import venv; print('venv OK')"
Output:
Python 3.12.3
pip 24.0 from /home/alice/.pyenv/versions/3.12.3/lib/python3.12/site-packages/pip (python 3.12)
venv OK
Common pitfalls
Externally managed environments — Debian 12+ and Ubuntu 23.04+ enforce PEP 668, blocking
pip installoutside a venv with the errorerror: externally-managed-environment. Always activate a virtual environment first. See venv.
Missing
python3-venv— On Ubuntu,python3 -m venvfails until you installpython3-venv(orpython3.12-venvfor a specific version):sudo apt install python3-venv.
Next steps
python3 -m venv .venv
source .venv/bin/activate
See Virtual Environments.
openSUSE / SLES
openSUSE Tumbleweed (rolling) and Leap (stable) use zypper and ship Python under versioned package names. Tumbleweed tends to track upstream within weeks; Leap aligns with SUSE Linux Enterprise and may be a release or two behind.
# Tumbleweed / Leap
sudo zypper refresh
sudo zypper install python312 python312-pip python312-devel
# SLES — first enable the Python module
sudo SUSEConnect --product sle-module-python3/15.5/x86_64
sudo zypper install python311 python311-pip
Output:
The following 3 NEW packages are going to be installed:
python312 python312-pip python312-devel
Continue? [y/n/v/...? shows all options] (y): y
Retrieving: python312-3.12.3-1.1.x86_64.rpm
openSUSE keeps the system
python3separate from the developer-installablepython312. Both can coexist;update-alternativesis not the openSUSE convention — useeselect-style links or just callpython3.12explicitly.
Alpine / musl-based distros
Alpine Linux (commonly used as a Docker base image) ships Python compiled against musl libc instead of glibc. Most wheels on PyPI assume glibc, so pure-Python packages install fine, but C-extension packages may need to be compiled from source — sometimes with extra system packages.
# Alpine apk
apk add --no-cache python3 py3-pip
# When you need to build C extensions
apk add --no-cache build-base python3-dev libffi-dev openssl-dev
Output:
(1/3) Installing python3 (3.12.3-r0)
(2/3) Installing py3-pip (24.0-r0)
(3/3) Installing py3-setuptools (69.5.1-r0)
OK: 84 MiB in 50 packages
If you see
error: invalid command 'bdist_wheel'orImportError: Error loading shared library, you are hitting the musl-vs-glibc wheel gap. Either install the matching-devpackages and let pip compile from source, or switch your base image topython:3.12-slim(Debian-based, glibc, prebuilt wheels work).
Gentoo
Gentoo's portage system compiles everything from source by default. The python USE flag selects which Python versions are available system-wide; eselect python chooses the default python3.
# Pull the current ebuild tree
sudo emerge --sync
# Install a specific Python slot
sudo emerge -av '=dev-lang/python-3.12*'
# Choose the default
sudo eselect python list
sudo eselect python set python3.12
Output:
Available Python interpreters, in order of preference:
[1] python3.11
[2] python3.12 *
NixOS / nix-shell
NixOS treats Python as a per-project derivation rather than a globally-installed package. A shell.nix declares which Python and which packages, and nix-shell materializes them in a hermetic environment.
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
packages = [
(pkgs.python312.withPackages (ps: with ps; [ requests rich pytest ]))
];
}
nix-shell # drops into a shell with Python 3.12 + packages
python --version
which python
Output:
Python 3.12.3
/nix/store/abc...-python3-3.12.3/bin/python
On NixOS, never
pip installsystem-wide — the read-only/nix/storewill refuse. Use a venv inside anix-shell, or declare dependencies inshell.nix.
Method — uv python install
uv downloads precompiled CPython tarballs (from the python-build-standalone project) and unpacks them under ~/.local/share/uv/python/. No build dependencies, no compilation, no root — and it works the same on Debian, Fedora, Arch, Alpine, and NixOS.
# Install uv itself
curl -LsSf https://astral.sh/uv/install.sh | sh
exec $SHELL # reload PATH
# Install Python
uv python install 3.12
uv python install 3.11 3.13
# List
uv python list
# Use without touching PATH
uv venv --python 3.12
uv run python --version
Output:
Installed Python 3.12.3 in 1.10s
+ cpython-3.12.3-linux-x86_64-gnu (python3.12)
The python-build-standalone tarballs uv uses are statically linked against musl-glibc compatibility shims — they run on most Linux distros including Alpine. The trade-off is that some niche extension modules (like those linking to system-wide BLAS) may behave differently than a from-source build.
Method — asdf and mise
Both are polyglot version managers that handle Python alongside Node, Ruby, Go, and dozens of others via plugins. Useful on shared dev machines, in CI runners that need a specific minor version, and on personal laptops where you already use them for other languages.
# asdf
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.0
echo '. "$HOME/.asdf/asdf.sh"' >> ~/.bashrc
source ~/.bashrc
asdf plugin add python
asdf install python 3.12.3
asdf global python 3.12.3
# mise — faster Rust-based successor
curl https://mise.run | sh
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
source ~/.bashrc
mise use --global python@3.12
mise current python
Output:
python 3.12.3 installation successful
mise python@3.12.3 ✓ installed
3.12.3
misereads the same.tool-versionsfile asasdfbut starts up in single-digit milliseconds rather than ~80 ms. If you are starting fresh in 2026, prefermise.
Method — conda / mamba / miniforge
For scientific computing, GPU machine learning, or polyglot data stacks (Python + R + C compilers + CUDA), the conda ecosystem manages Python and the native libraries it links against.
# Install Miniforge (community fork, defaults to conda-forge, no Anaconda license risk)
curl -LO "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
bash Miniforge3-$(uname)-$(uname -m).sh -b -p ~/miniforge3
~/miniforge3/bin/conda init bash
exec $SHELL
# Create an environment
mamba create -n ml python=3.12 numpy pandas pytorch cuda-version=12.4 -c pytorch -c nvidia
mamba activate ml
python -c "import torch; print(torch.cuda.is_available())"
Output:
Looking for: ['python=3.12', 'numpy', 'pandas', 'pytorch', 'cuda-version=12.4']
+ python 3.12.3-h99e199e_0
+ pytorch 2.3.0-cu124_py312
done
True
System Python vs user-managed Python
Every Linux distro ships a Python that other system tools depend on. Treat it as a runtime for those tools — not a development environment.
| Tool that depends on system Python | Distro |
|---|---|
apt, add-apt-repository, unattended-upgrades | Debian/Ubuntu |
dnf, yum, firewalld, cloud-init | Fedora/RHEL |
pacman (some scripts), mkinitcpio | Arch |
zypper (helpers), YaST | openSUSE |
cloud-init, salt-minion (everywhere) | Many distros |
Rules:
- Never
sudo pip installagainst the system Python. PEP 668 blocks this on modern Debian/Ubuntu (and Fedora 38+) for a good reason. - Never replace
/usr/bin/python3with a different version viaupdate-alternatives. System scripts have shebangs like#!/usr/bin/python3and assume the distro's exact build. - Always work inside a virtual environment, a uv-managed Python, a pyenv-managed Python, or a conda env.
- To install a few CLI tools globally for your user (not system), prefer
pipx(apt install pipxorpip install --user pipx).
# Wrong — will be blocked by PEP 668 on modern distros
sudo pip install httpie
# Right — pipx installs each tool in its own venv under ~/.local/pipx
sudo apt install pipx
pipx ensurepath
pipx install httpie
Output:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to install.
installed package httpie 3.2.2, installed using Python 3.12.3
These apps are now globally installed
- http
- https
- httpie
done! ✨ 🌟 ✨
Container / Docker approach
For reproducible builds, CI, and ephemeral dev environments, the official python image on Docker Hub is well-curated. Pick the variant that matches your use case:
| Tag | Base | Size | When to use |
|---|---|---|---|
python:3.12 | Debian | ~1 GB | Maximum compatibility, all wheels work |
python:3.12-slim | Debian (minimal) | ~150 MB | Production — small, glibc, almost all wheels work |
python:3.12-alpine | Alpine (musl) | ~50 MB | Smallest, but C extensions may need compilation |
python:3.12-bookworm | Pinned to specific Debian | ~1 GB | Long-term reproducibility |
python:3.12-bullseye | Older Debian | ~1 GB | Maximum wheel compatibility |
# Production-grade Dockerfile
FROM python:3.12-slim AS builder
WORKDIR /app
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir uv
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project
FROM python:3.12-slim
COPY --from=builder /app/.venv /app/.venv
COPY . /app
WORKDIR /app
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "myapp"]
# Drop into a one-shot Python 3.12 shell, no install needed
docker run --rm -it python:3.12-slim bash
Output:
Unable to find image 'python:3.12-slim' locally
Pulling fs layer
Downloaded newer image for python:3.12-slim
root@9f3b2:/# python --version
Python 3.12.3
Verification recipes
After any install, run these to confirm the result.
# Where is python3 resolving from?
which -a python3
type -a python3
# Version
python3 --version
# Is pip wired to the same interpreter?
python3 -m pip --version
# Does the venv module work?
python3 -m venv /tmp/_probe && rm -rf /tmp/_probe && echo 'venv OK'
# Does SSL work?
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
# Does sqlite3 work? (commonly missing on minimal source builds)
python3 -c "import sqlite3; print(sqlite3.sqlite_version)"
# Does the build of Python include all stdlib modules?
python3 -c "import bz2, lzma, ctypes, hashlib, ssl, sqlite3, zlib, readline, tkinter; print('all good')"
# Can pip reach PyPI?
python3 -m pip install --dry-run --user requests
Output:
/home/alice/.pyenv/shims/python3
/usr/bin/python3
Python 3.12.3
pip 24.0 from /home/alice/.pyenv/versions/3.12.3/lib/python3.12/site-packages/pip (python 3.12)
venv OK
OpenSSL 3.0.13 30 Jan 2024
3.46.0
all good
Would install requests-2.32.3 certifi-2024.7.4 charset-normalizer-3.3.2 idna-3.7 urllib3-2.2.2
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
error: externally-managed-environment | PEP 668 enforced on modern Debian/Ubuntu/Fedora | Use a venv, pipx, or uv instead of system pip |
python3 -m venv fails with ensurepip is not available | python3-venv package not installed | sudo apt install python3-venv |
ModuleNotFoundError: No module named '_ssl' after source build | Missing libssl-dev at compile time | Reinstall libssl-dev, rebuild: ./configure --enable-optimizations && make -j$(nproc) && sudo make altinstall |
ModuleNotFoundError: No module named '_sqlite3' | Missing libsqlite3-dev at compile time | Same as above with libsqlite3-dev |
pip install is slow on Raspberry Pi or ARM | No wheels for arm64/armv7 — pip compiles from source | Switch to piwheels: pip install --extra-index-url https://www.piwheels.org/simple/ |
dnf install python3.12 returns "No match" on RHEL | EPEL repo not enabled | sudo dnf install epel-release |
add-apt-repository: command not found | software-properties-common missing | sudo apt install software-properties-common |
SSL: CERTIFICATE_VERIFY_FAILED from pip | System CA bundle missing or stale | sudo apt install --reinstall ca-certificates && sudo update-ca-certificates |
pyenv install fails on _uuid module | Missing uuid-dev | sudo apt install uuid-dev |
Common pitfalls (extended)
update-alternativesforpython— Don't repoint/usr/bin/python3away from the distro default. Even Ubuntu's ownupdate-managerwill break ifpython3doesn't behave the way Canonical's scripts expect.
PPAs are not always trustworthy —
ppa:deadsnakes/ppais widely used and maintained, but other PPAs may be unmaintained. Always check the PPA's update frequency before adding it to a production system.
/tmponnoexecmount — Some hardened distros mount/tmpwithnoexec, which breakspipwhen it tries to execute build scripts from/tmp. SetTMPDIRto a writable, executable location:TMPDIR=$HOME/.cache/pip-tmp pip install <pkg>.
For air-gapped environments (no internet from the build host), use
pip downloadon a connected host to grab wheels, thenpip install --no-index --find-links=./wheels <pkg>on the target.
Real-world recipes
Fresh Ubuntu 24.04 in three commands
sudo apt update && sudo apt install -y python3 python3-venv python3-pip pipx
pipx ensurepath
pipx install uv
Newest Python on Ubuntu 22.04 LTS
sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt update
sudo apt install -y python3.13 python3.13-venv python3.13-dev
python3.13 --version
Locked-down server with no root access
# Install everything to ~/.local — no sudo anywhere
curl -LsSf https://astral.sh/uv/install.sh | sh
~/.local/bin/uv python install 3.12
~/.local/bin/uv venv --python 3.12
source .venv/bin/activate
Reproducible CI install (GitHub Actions on Linux runners)
jobs:
test:
strategy:
matrix:
python: ['3.11', '3.12', '3.13']
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- run: uv python install ${{ matrix.python }}
- run: uv sync --frozen
- run: uv run pytest
Building Python from source with full optimisation
sudo apt install -y build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev libffi-dev libncurses5-dev libgdbm-dev \
liblzma-dev tk-dev uuid-dev
curl -LO https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tgz
tar xf Python-3.12.3.tgz
cd Python-3.12.3
./configure \
--enable-optimizations \
--with-lto \
--enable-shared \
--with-ensurepip=install \
--prefix=/opt/python/3.12.3
make -j"$(nproc)"
sudo make altinstall
/opt/python/3.12.3/bin/python3.12 --version
Cleaning up an old install
# apt-installed
sudo apt remove --purge python3.11 python3.11-* && sudo apt autoremove
# pyenv-installed
pyenv uninstall 3.12.3
# Source-installed via altinstall
sudo rm /usr/local/bin/python3.12 /usr/local/bin/pip3.12
sudo rm -rf /usr/local/lib/python3.12
# uv-installed
uv python uninstall 3.12
# Verify
which -a python3 python3.12 python3.13
Next steps
python3 -m venv .venv
source .venv/bin/activate
See Virtual Environments, pip vs uv, and apt-get for deeper coverage.