Що таке devpi і навіщо
devpi — це приватний PyPI з вбудованим кешем публічного PyPI, керуванням користувачами та індексами. Ви отримуєте:
- внутрішнє сховище для власних пакетів;
- дзеркало публічного PyPI для швидкості та надійності;
- веб‑інтерфейс (через плагін devpi-web) і API для автоматизації;
- просту інтеграцію з Nginx і systemd.
Це класичний кейс для сервер Linux в компанії або лабораторії, де доступ до Інтернету обмежений або потрібен контроль над залежностями.
Підготовка оточення
Встановлення devpi
Нижче — універсальний спосіб через віртуальне оточення Python в Linux (пакети системи не чіпаємо):
# 1) Створюємо системного користувача та каталоги
sudo useradd --system --create-home --home-dir /srv/devpi --shell /usr/sbin/nologin devpi
sudo install -d -o devpi -g devpi -m 0750 /srv/devpi /srv/devpi/data
# 2) Ставимо devpi в окремий venv
sudo -u devpi python3 -m venv /srv/devpi/venv
sudo -u devpi /srv/devpi/venv/bin/pip install --upgrade pip
sudo -u devpi /srv/devpi/venv/bin/pip install 'devpi-server[threading]' devpi-client devpi-web
# 3) Початкова ініціалізація сховища
sudo -u devpi /srv/devpi/venv/bin/devpi-init --serverdir /srv/devpi/data
Початкове налаштування користувача та індексу
# Тимчасово стартуємо сервер локально (для первинної конфігурації)
sudo -u devpi /srv/devpi/venv/bin/devpi-server \
--serverdir /srv/devpi/data --host 127.0.0.1 --port 3141 &
# Налаштовуємо root пароль і створюємо окремого користувача та індекс
sudo -u devpi /srv/devpi/venv/bin/devpi use http://127.0.0.1:3141
sudo -u devpi /srv/devpi/venv/bin/devpi login root --password ''
sudo -u devpi /srv/devpi/venv/bin/devpi user -m root password 'StrongPass!'
sudo -u devpi /srv/devpi/venv/bin/devpi user -c company password 'S3cret!'
sudo -u devpi /srv/devpi/venv/bin/devpi login company --password 'S3cret!'
sudo -u devpi /srv/devpi/venv/bin/devpi index -c company/dev bases='root/pypi' volatile=false
# Зупиняємо тимчасовий процес devpi-server (якщо він у фоні)
pkill -f 'devpi-server.*3141' || true
Запуск через systemd
Сервіс під systemd дасть автозапуск, рестарт при збої і логування. Це якраз той випадок, де згодиться практика cron та systemd timers для резервних завдань.
# Створюємо юніт /etc/systemd/system/devpi.service (права root)
cat <<'EOF' | sudo tee /etc/systemd/system/devpi.service >/dev/null
[Unit]
Description=devpi private PyPI
After=network-online.target
Wants=network-online.target
[Service]
User=devpi
Group=devpi
ExecStart=/srv/devpi/venv/bin/devpi-server --serverdir /srv/devpi/data \
--host 127.0.0.1 --port 3141 --threads 4
Restart=on-failure
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now devpi
sudo systemctl status devpi --no-pager -l
Реверс‑проксі через Nginx
Nginx додасть TLS, ліміти розміру завантажень і зручний домен. Ось базове nginx налаштування:
# Конфіг /etc/nginx/sites-available/devpi.conf
sudo tee /etc/nginx/sites-available/devpi.conf >/dev/null <<'EOF'
server {
listen 80;
server_name pypi.example.lan;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:3141;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
}
}
EOF
# Активація сайту
sudo ln -s /etc/nginx/sites-available/devpi.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Для внутрішніх доменів зазвичай достатньо HTTP, але краще додати TLS (власний корпоративний сертифікат або ACME).
Використання: інсталяція та публікація пакетів
Налаштування pip для інсталяції
# Створюємо конфіг користувача pip на робочих станціях
mkdir -p ~/.config/pip
cat <<'EOF' > ~/.config/pip/pip.conf
[global]
index-url = https://pypi.example.lan/company/dev/+simple/
EOF
# Перевірка інсталяції пакета з вашого індексу
python3 -m pip install requests
Якщо у вас самопідписаний TLS, додайте довірений корінний сертифікат у систему або використайте параметр trusted-host у тимчасових випадках.
Публікація власних пакетів
# У каталозі вашого пакета
python3 -m pip install --upgrade build twine
python3 -m build
# Завантаження у приватний індекс
TWINE_USERNAME=company TWINE_PASSWORD='S3cret!' \
twine upload --repository-url 'https://pypi.example.lan/company/dev/' dist/*
Після завантаження ваші колеги зможуть ставити пакет прямо з devpi. Це дуже зручно для python в Linux середовищах розробки та CI.
Альтернативні способи
Docker та контейнеризація
Швидкий старт у контейнері, якщо вам ближча Docker на сервері:
# Мінімальний запуск devpi у контейнері (дані збережуться у volume)
sudo docker run -d --name devpi \
-p 127.0.0.1:3141:3141 \
-v devpi-data:/data \
devpi/devpi
Далі знову ставимо Nginx спереду. Плюс контейнеризація спрощує оновлення.
TLS і контроль доступу
devpi вже має аутентифікацію, а Nginx може додати IP‑обмеження чи mTLS. Для мінімального захисту в локальній мережі достатньо залишити devpi на 127.0.0.1 і випускати зовні тільки Nginx 🛡️
GUI‑спосіб: devpi-web
Плагін devpi-web вже встановили. Він додає веб‑інтерфейс огляду пакетів та індексів.
- Відкрийте https://pypi.example.lan у браузері.
- Увійдіть як ваш користувач (наприклад, company).
- Переглядайте індекси, шукайте пакети, дивіться метадані та історію завантажень.
FAQ
Devpi не стартує як сервіс.
Перевірте логи: journalctl -u devpi -e. Часто це права на /srv/devpi/data або помилки у шляху до venv.
Отримую 413 Request Entity Too Large при завантаженні.
Підніміть client_max_body_size у Nginx (наприклад, 200M), перезавантажте Nginx.
pip лається на сертифікат.
Додайте корпоративний корінний сертифікат у системне сховище та в CA для Python. Тимчасово можна додати trusted-host або використати HTTP у закритій мережі.
Як оновити devpi без простою?
Робіть бекап, зупиняйте сервіс, оновлюйте пакети у venv, запускайте міграцію схемою devpi-server --export/--import за потреби, потім стартуйте. Тримайте Nginx із сторінкою 503‑maintenance на час вікна.
Чи можна віддати тільки кеш PyPI без власних пакетів?
Так, використовуйте індекс root/pypi напряму як index-url.
Де логи Nginx?/var/log/nginx/access.log та /var/log/nginx/error.log. Перевіряйте також nginx -t після змін.
Порада від Kernelka
Зробіть простий резервний копіювальник через systemd timer, щоб не згадувати про бекапи в останню хвилину.
# Скрипт бекапу /usr/local/bin/devpi-backup
sudo tee /usr/local/bin/devpi-backup >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
TS=$(date +%F-%H%M)
mkdir -p /var/backups
sudo tar -czf /var/backups/devpi-$TS.tgz -C /srv/devpi data
EOF
sudo chmod +x /usr/local/bin/devpi-backup
# Юніт і таймер для щоденного бекапу о 2:30
sudo tee /etc/systemd/system/devpi-backup.service >/dev/null <<'EOF'
[Unit]
Description=Backup devpi data
[Service]
Type=oneshot
ExecStart=/usr/local/bin/devpi-backup
EOF
sudo tee /etc/systemd/system/devpi-backup.timer >/dev/null <<'EOF'
[Unit]
Description=Daily devpi backup
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now devpi-backup.timer
Підсумок
- Розгорнули devpi як приватний PyPI за Nginx на сервер Linux.
- Запустили сервіс через systemd і налаштували доступ за доменом.
- Налаштували pip для інсталяції та twine для публікації пакетів.
- Додали резервне копіювання через cron та systemd timers і отримали базовий GUI.
- Тепер внутрішні Python‑пакети розгортаються швидко і безпечно ✅

Прокоментувати
На сайті відображається лише твоє ім'я та коментар. Електронна пошта зберігається виключно для зв'язку з тобою за потреби та в жодному разі не передається стороннім особам.