PyPI Server 服务安装部署文档
本文档可直接用于 AI 部署,包含完整的服务安装步骤和配置
环境信息
| 项目 |
版本/说明 |
| 操作系统 |
CentOS 7 |
| Python管理 |
Anaconda3 |
| Python版本 |
3.11.5 |
| 反向代理 |
Nginx |
部署架构
┌─────────────┐
│ Nginx │
│ :8080 │
└──────┬──────┘
│
┌──────▼──────┐
│ pypiserver │
│ :28081 │
│ (认证访问) │
└──────┬──────┘
│
┌──────▼──────┐
│ /app/pypi │
│ /packages │
└─────────────┘
上传方式: pip download → Xftp → /app/pypi-server/packages/
一、基础环境准备
1.1 系统依赖安装
# 安装系统基础工具
yum install -y wget curl vim
# 安装 nginx
yum install -y epel-release
yum install -y nginx
# 安装 htpasswd 工具(用于生成密码文件)
yum install -y httpd-tools
1.2 Anaconda3 环境准备
# 假设 Anaconda3 已安装,创建独立的 Python 3.11.5 环境
conda create -n pypi-server python=3.11.5 -y
# 激活环境
conda activate pypi-server
二、PyPI Server 部署
2.1 创建目录结构
# 创建 pypiserver 工作目录
mkdir -p /app/pypi-server/packages
mkdir -p /app/pypi-server/logs
# 设置目录权限
chmod 755 /app/pypi-server
chmod 755 /app/pypi-server/packages
chmod 755 /app/pypi-server/logs
2.2 安装 pypiserver
# 激活 conda 环境
conda activate pypi-server
# 安装 pypiserver
pip install pypiserver[passlib]
2.3 配置认证账号
# 创建密码文件(添加第一个用户)
# 替换 YOUR_USERNAME 和 YOUR_PASSWORD 为实际值
htpasswd -bc /app/pypi-server/.htpasswd YOUR_USERNAME YOUR_PASSWORD
# 示例:创建 admin 用户
htpasswd -bc /app/pypi-server/.htpasswd admin Admin@2025
# 添加更多用户(不要带 -c 参数,会覆盖文件)
# htpasswd -b /app/pypi-server/.htpasswd ANOTHER_USER ANOTHER_PASSWORD
# 设置密码文件权限(只读)
chmod 644 /app/pypi-server/.htpasswd
2.4 创建 systemd 服务
cat > /etc/systemd/system/pypi-server.service << 'EOF'
[Unit]
Description=PyPI Server
After=network.target
[Service]
Type=simple
User=root
Environment="PATH=/root/anaconda3/envs/pypi-server/bin:/usr/local/bin:/usr/bin:/bin"
WorkingDirectory=/app/pypi-server
ExecStart=/root/anaconda3/envs/pypi-server/bin/pypi-server run \
-p 28081 \
-i 0.0.0.0 \
-a download,list \
-P /app/pypi-server/.htpasswd \
--disable-fallback \
--overwrite \
/app/pypi-server/packages
Restart=always
RestartSec=10
StandardOutput=append:/app/pypi-server/logs/pypi-server.log
StandardError=append:/app/pypi-server/logs/pypi-server-error.log
[Install]
WantedBy=multi-user.target
EOF
# 重载 systemd
systemctl daemon-reload
# 启动服务
systemctl start pypi-server
# 设置开机自启
systemctl enable pypi-server
# 检查服务状态
systemctl status pypi-server
2.5 参数说明
| 参数 |
说明 |
run |
pypiserver 2.x 必须使用的子命令 |
-p 28081 |
监听端口 28081 |
-i 0.0.0.0 |
监听所有网络接口 |
-a download,list |
需要认证的操作(download=下载, list=列表) |
-P |
指定 htpasswd 密码文件路径 |
--disable-fallback |
禁止从 PyPI 官方代理下载 |
--overwrite |
允许覆盖同名包 |
三、Nginx 反向代理配置
3.1 创建 nginx 配置
cat > /etc/nginx/conf.d/pypi-server.conf << 'EOF'
server {
listen 8080;
server_name _;
# 日志配置
access_log /var/log/nginx/pypi-access.log;
error_log /var/log/nginx/pypi-error.log;
# 禁止 POST/PUT/DELETE 请求(只允许下载,禁止上传)
if ($request_method !~ ^(GET|HEAD)$) {
return 403;
}
# 禁止访问首页(web 界面)
location = / {
return 403;
}
# 允许包列表和下载接口 /simple/
location /simple/ {
proxy_pass http://127.0.0.1:28081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Authorization $http_authorization;
proxy_pass_header WWW-Authenticate;
proxy_pass_header Authorization;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
# 允许包文件下载 /packages/
location /packages/ {
proxy_pass http://127.0.0.1:28081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Authorization $http_authorization;
proxy_pass_header WWW-Authenticate;
proxy_pass_header Authorization;
}
# 其他所有路径禁止访问
location / {
return 403;
}
}
EOF
3.2 启动 nginx
# 测试配置
nginx -t
# 启动 nginx
systemctl start nginx
# 设置开机自启
systemctl enable nginx
# 检查状态
systemctl status nginx
3.3 安全配置说明
pypiserver 路径说明
/simple/ # 包列表接口(pip 访问获取包信息)
/simple/{pkg}/ # 单个包的信息页面
/packages/ # 包文件实际存储路径(pip 下载 .whl 文件)
安全限制表
| 限制项 |
配置方式 |
目的 |
| 禁止 Web 首页 |
location = / { return 403; } |
防止访问 web 界面 |
| 允许包列表 |
代理 /simple/ |
pip 获取包列表 |
| 允许包下载 |
代理 /packages/ |
pip 下载 .whl 文件 |
| 禁止上传 |
if ($request_method !~ ^(GET|HEAD)$) |
禁止 POST/PUT/DELETE |
| 禁止其他路径 |
location / { return 403; } |
阻止未授权访问 |
允许的访问
✅ GET http://SERVER:8080/simple/ # 包列表(需认证)
✅ GET http://SERVER:8080/simple/{pkg}/ # 包信息页(需认证)
✅ GET http://SERVER:8080/packages/*/*.whl # 包文件下载(需认证)
✅ HEAD http://SERVER:8080/simple/* # HEAD 请求
禁止的访问
❌ GET http://SERVER:8080/ # 首页(403 Forbidden)
❌ POST/PUT/DELETE 任何路径 # 上传操作(403 Forbidden)
❌ GET http://SERVER:8080/favicon.ico # 静态资源(403 Forbidden)
❌ 其他未定义路径 # (403 Forbidden)
四、防火墙配置
# 开放 nginx 端口
firewall-cmd --permanent --add-port=8080/tcp
# 重载防火墙
firewall-cmd --reload
五、包上传方式
5.1 在有网络的机器上下载包
# 下载单个包(包含依赖)
pip download -d ./packages package-name
# 下载多个包
pip download -d ./packages package1 package2 package3
# 根据 requirements.txt 下载
pip download -d ./packages -r requirements.txt
# 指定 Python 版本
pip download -d ./packages --python-version 3.11 package-name
# 指定平台
pip download -d ./packages --only-binary=:all: package-name
5.2 上传包到服务器
使用 Xftp 或其他 SFTP 工具上传:
本地目录: ./packages/*.whl
上传目标: /app/pypi-server/packages/
5.3 验证包是否生效
# 查看已上传的包
ls -lh /app/pypi-server/packages/
# 测试访问
curl -u admin:Admin@2025 http://SERVER_IP:8080/simple/
六、验证部署
# 1. 检查 pypiserver 服务(本地端口 28081)
curl -I http://127.0.0.1:28081/
# 2. 检查 nginx 代理(外部端口 8080)
curl -I http://127.0.0.1:8080/
# 3. 测试带认证访问
curl -u admin:Admin@2025 http://127.0.0.1:8080/simple/
# 4. 测试无认证访问(应该返回 401)
curl -I http://127.0.0.1:8080/simple/
七、服务管理命令
# pypiserver 管理
systemctl start pypi-server # 启动
systemctl stop pypi-server # 停止
systemctl restart pypi-server # 重启
systemctl status pypi-server # 状态
journalctl -u pypi-server -f # 查看日志
# nginx 管理
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
systemctl status nginx
八、故障排查
8.1 服务无法启动
# 查看详细日志
journalctl -u pypi-server -n 50
tail -f /app/pypi-server/logs/pypi-server-error.log
8.2 认证失败
# 检查密码文件
cat /app/pypi-server/.htpasswd
# 重新生成密码
htpasswd -bc /app/pypi-server/.htpasswd username newpassword
8.3 下载 401 错误
- 检查
-a download,list 参数是否正确配置
- 确认 nginx 正确传递了 Authorization 头
- 验证密码文件权限正确(644)
九、目录结构
/app/pypi-server/
├── packages/ # Python 包存储目录
├── logs/ # 日志目录
│ ├── pypi-server.log
│ └── pypi-server-error.log
└── .htpasswd # 认证密码文件
/etc/nginx/conf.d/
└── pypi-server.conf # Nginx 配置
/etc/systemd/system/
└── pypi-server.service # systemd 服务文件