Ubuntu 22.04 安装 BounCA 0.4.8 指南

Ubuntu 22.04.5 直装 BounCA 0.4.8 实测:官方发行包下载与 sha256 校验、PostgreSQL 14 建库、services.yaml 下发、venv 依赖安装、migrate/collectstatic/site/createsuperuser、Nginx+uWSGI systemd 托管与四端点 200/API 登录验证,附源码方案差异与六条真实排障实录。

BounCABounCAUbuntu22.04Python 编程2026/10/28

Ubuntu 22.04 安装 BounCA 0.4.8 指南

目标:在一台 Ubuntu 22.04 服务器上从零完成 BounCA 0.4.8 的生产化直装——Python/Django 应用栈 + PostgreSQL 14 + Nginx/uWSGI,涵盖发行包下载与校验、数据库初始化、配置下发、systemd 托管、Web 与 API 登录验证,以及源码方案的差异说明与真实排障实录。全部命令与回显均在实测机上逐条执行照抄。组件定位与选型背景见《BounCA 介绍与选型指南》。

一、环境信息

实测机配置(命令与回显均为实测机原样输出):

$ uname -r
7.0.0-38-generic
$ nproc
6
$ free -h | sed -n 2p
Mem:            18Gi       5.3Gi       2.4Gi       202Mi        11Gi        13Gi
$ hostname -I
10.89.70.10

软件版本基线(安装后实查):

组件版本来源
操作系统Ubuntu 22.04.5 LTS/etc/os-release
Python3.10.12系统自带 python3
PostgreSQL14.24apt(Ubuntu 22.04 官方仓库)
Nginx1.18.0(nginx/1.18.0 (Ubuntu))apt
uWSGI2.0.20(uwsgi 2.0.20-4 / uwsgi-plugin-python3 同版)apt
BounCA0.4.8(官方 GitLab Packages 发行包)本篇实测

约定:下文以 /srv/www 作为应用根目录,www-data 为应用运行用户(与 Nginx/uWSGI 默认用户一致),服务器内网地址 10.89.70.10。

二、前置条件

2.1 系统依赖安装

按官方 README 的清单安装(BounCA 官方教程以 Debian 11 为例,Ubuntu 22.04 依赖同名包):

# apt-get install -y \
    gettext \
    nginx \
    python3 \
    python3-dev \
    python3-setuptools \
    python-is-python3 \
    uwsgi \
    uwsgi-plugin-python3 \
    virtualenv \
    python3-virtualenv \
    python3-pip \
    postgresql \
    postgresql-contrib

实测机执行后的收尾回显(部分包此前已就绪):

python3-dev is already the newest version (3.10.6-1~22.04.1).
python3-setuptools is already the newest version (59.6.0-1.2ubuntu0.22.04.3).
python3-pip is already the newest version (22.0.2+dfsg-1ubuntu0.7).
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.

版本确认:

# dpkg -l | grep -E "^ii  (nginx|postgresql-14|uwsgi) "
nginx 1.18.0-6ubuntu14.22
postgresql-14 14.24-0ubuntu0.22.04.1
uwsgi 2.0.20-4

2.2 运行目录准备

# mkdir -p /srv/www
# mkdir -p /var/log/bounca
# chown -R www-data:www-data /var/log/bounca

排障提示:/var/log/bounca 忘记授权给 www-data 是官方 README 点名的经典坑——uWSGI 起动后报 no python application found, check your startup logs for errors 时先查这里(见第八节 FAQ-5)。

三、版本选型说明

BounCA 官方仅通过 GitLab Packages 发布通用发行包(无 PPA/apt 仓库、无 PyPI 包)。选型结论:生产环境使用官方发行包 0.4.8,理由与依据:

  1. 0.4.8 为最新稳定版,2026-02-05 发布(官方 changelog);
  2. 发行包自带预构建的 Vuetify 前端(front/dist)与依赖锁定文件 requirements.txt(uv 编译产物,版本全部锁定),开箱即可部署;
  3. 0.4.7(2026-01-09)修复私钥导出、0.4.8(2026-02-05)新增到期邮件提醒并支持 Debian 13,连发三版说明 0.4.x 线处于活跃维护期。

发行包下载地址(GitLab Packages 官方 API 实查):

https://gitlab.com/bounca/bounca/-/package_files/267456786/download

四、安装方案 A:官方发行包(推荐)

4.1 下载与完整性校验

# cd /srv/www
# wget https://gitlab.com/bounca/bounca/-/package_files/267456786/download -O bounca-0.4.8.tar.gz
# sha256sum bounca-0.4.8.tar.gz
28335d205985ad30a5fc3bbc62db0bb24035cd0f3748790fb483defb9c8ea91b  bounca-0.4.8.tar.gz

sha256 与 GitLab Packages API 返回的 file_sha256(28335d20…c8ea91b,文件大小 4427992 字节)一致,校验通过。实测机重复下载比对亦一致。

4.2 解包与属主

发行包内含一级目录 bounca/,解包到 /srv/www 后即得到 /srv/www/bounca:

# tar -xvzf bounca-0.4.8.tar.gz
./
./bounca/
./bounca/vuetifyforms/
./bounca/vuetifyforms/tests/
./bounca/vuetifyforms/tests/test_vue_flex.py
./bounca/vuetifyforms/tests/test_validator.py
...
# tar -tzf bounca-0.4.8.tar.gz | wc -l
272
# chown www-data:www-data -R /srv/www/bounca

4.3 创建 PostgreSQL 库与账号

# su - postgres
$ createuser bounca
$ createdb --owner=bounca bounca --encoding=UTF8 --template=template0
$ psql -c "ALTER USER bounca WITH createdb" postgres
ALTER ROLE
$ psql -c "ALTER USER bounca WITH PASSWORD 'q1w2e3r4'" postgres
ALTER ROLE
$ exit

建库结果核验(\l 节选):

$ su - postgres -c "psql -c '\l'"
                              List of databases
   Name    |  Owner   | Encoding | Collate |  Ctype  |   Access privileges
-----------+----------+----------+---------+---------+-----------------------
 bounca    | bounca   | UTF8     | C.UTF-8 | C.UTF-8 |
 postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
 template0 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
 template1 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
(4 rows)

4.4 下发 BounCA 配置(services.yaml)

/etc/bounca/services.yaml 是全实例唯一必须人工下发的应用配置(三层合并与逐参数语义见《BounCA 0.4.8 配置参数详解》):

# mkdir -p /etc/bounca
# cp /srv/www/bounca/etc/bounca/services.yaml.example /etc/bounca/services.yaml

按实测机情况修改(数据库指向本机、注入随机 secret、Host 白名单加入本机地址),成稿如下(secret_key 为 python3 -c "import secrets; print(secrets.token_urlsafe(48))" 生成的随机串,此处隐去实际值):

psql:
  dbname: bounca
  username: bounca
  password: q1w2e3r4
  host: 127.0.0.1
  port: 5432

admin:
  enabled: True
  superuser_signup: False

django:
  debug: False
  secret_key: '<你的随机 48 字节串>'
  hosts:
    - localhost
    - 127.0.0.1
    - 10.89.70.10

mail:
  host: localhost
  admin: admin@example.com
  from: no-reply@example.com

certificate-engine:
  key_algorithm: rsa

registration:
  email_verification: off

4.5 创建虚拟环境并安装依赖

属主关键点:virtualenv 应由应用运行用户(www-data)持有——实测中先以 root 创建 env 再切 www-data 安装依赖会触发 Permission denied(见第八节 FAQ-1),因此统一用 www-data 完成 venv 全流程:

# cd /srv/www/bounca
# su -s /bin/bash www-data
$ virtualenv env -p python3
$ env/bin/pip install -r requirements.txt

pip install 实测收尾回显(36 个包全部按 requirements.txt 锁定版本安装):

Successfully built dj-rest-auth yamlreader
Installing collected packages: pytz, django-grappelli, urllib3, uritemplate, tzdata, typing-extensions, sqlparse, six, pyyaml, pycparser, psycopg2-binary, packaging, inflection, idna, charset-normalizer, certifi, bcrypt, yamlreader, requests, python-dateutil, cffi, asgiref, icalendar, django-countries, django, cryptography, arrow, djangorestframework, django-recurrence, django-filter, django-cors-headers, django-allauth, drf-yasg, django-property-filter, django-ical, dj-rest-auth
Successfully installed arrow-1.4.0 asgiref-3.11.1 bcrypt-5.0.0 certifi-2026.1.4 cffi-2.0.0 charset-normalizer-3.4.4 cryptography-46.0.4 dj-rest-auth-7.0.2 django-5.2.11 django-allauth-65.14.0 django-cors-headers-4.9.0 django-countries-8.2.0 django-filter-25.2 django-grappelli-4.0.3 django-ical-1.9.2 django-property-filter-1.3.0 django-recurrence-1.14 djangorestframework-3.16.1 drf-yasg-1.21.14 icalendar-6.3.2 idna-3.11 inflection-0.5.1 packaging-26.0 psycopg2-binary-2.9.11 pycparser-3.0 python-dateutil-2.9.0.post0 pytz-2025.2 pyyaml-6.0.3 requests-2.32.5 six-1.17.0 sqlparse-0.5.5 typing-extensions-4.15.0 tzdata-2025.3 uritemplate-4.2.0 urllib3-2.6.3 yamlreader-3.0.4

4.6 初始化数据库与静态资源

$ cd /srv/www/bounca
$ env/bin/python manage.py migrate

实测回显(尾段;首段含 Operations to perform: Apply all migrations: account, admin, api, auth, authtoken, contenttypes, sessions, sites, socialaccount, x509_pki):

  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_last_name_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying authtoken.0001_initial... OK
  Applying authtoken.0002_auto_20160226_1747... OK
  Applying authtoken.0003_tokenproxy... OK
  Applying authtoken.0004_alter_tokenproxy_options... OK
  Applying sessions.0001_initial... OK
  Applying sites.0001_initial... OK
  Applying sites.0002_alter_domain_unique... OK
  Applying socialaccount.0001_initial... OK
  Applying socialaccount.0002_token_max_lengths... OK
  Applying socialaccount.0003_extra_data_default_dict... OK
  Applying socialaccount.0004_app_provider_id_settings... OK
  Applying socialaccount.0005_socialtoken_nullable_app... OK
  Applying socialaccount.0006_alter_socialaccount_extra_data... OK
  Applying x509_pki.0005_alter_certificate_crl_distribution_url... OK
  Applying x509_pki.0006_keystore_p12_legacy... OK
  Applying x509_pki.0007_certificate_expire_warning_mail_sent_at... OK

说明:manage.py 首次运行会输出三条来自 dj_rest_auth 的 UserWarning(USERNAME_REQUIRED is deprecated 等弃用告警),属上游依赖告警,不影响部署,可忽略。

$ env/bin/python manage.py collectstatic --noinput

1013 static files copied to '/srv/www/bounca/media/static'.
$ env/bin/python manage.py site bounca.lab.internal
Setting site Frontend URI to: bounca.lab.internal

site 命令把前端回调域名写入 Django Sites 表(登录/邮件链接用它拼接),库内核验:

$ su - postgres -c "psql -d bounca -c 'SELECT domain, name FROM django_site'"
       domain        |    name
---------------------+------------
 bounca.lab.internal | BounCA PKI
(1 row)

4.7 创建管理员账号

$ DJANGO_SUPERUSER_PASSWORD=q1w2e3r4 env/bin/python manage.py createsuperuser --noinput --username admin --email admin@example.com
Superuser created successfully.

4.8 下发 Nginx 与 uWSGI 站点配置

# cp /srv/www/bounca/etc/nginx/bounca /etc/nginx/sites-available/bounca
# ln -s /etc/nginx/sites-available/bounca /etc/nginx/sites-enabled/bounca
# rm -f /etc/nginx/sites-enabled/default
# cp /srv/www/bounca/etc/uwsgi/bounca.ini /etc/uwsgi/apps-available/bounca.ini
# ln -s /etc/uwsgi/apps-available/bounca.ini /etc/uwsgi/apps-enabled/bounca.ini

两处必改(发行包模板默认按 GitLab 演示环境写死):

  1. Nginx server_name 改为本机(或用 _ 兜底):sed -i "s/server_name bounca;/server_name _;/" /etc/nginx/sites-available/bounca;
  2. /etc/bounca/services.yaml 的 django.hosts 白名单需包含实际访问域名/IP(与 server_name 一致),否则请求会被 Django DisallowedHost 拦截(实测见 C 篇)。

若计划改用 gunicorn 替代 uWSGI:env/bin/pip install gunicorn 后以 env/bin/gunicorn -w 4 -b 127.0.0.1:8000 bounca.wsgi:application 起进程、Nginx proxy_pass http://127.0.0.1:8000; 即可,其余步骤完全一致;本文按官方默认 uWSGI 路径实测。

4.9 启动服务(systemd 托管)

Ubuntu 22.04 的 uWSGI/Nginx/PostgreSQL 均由 systemd 托管(uWSGI 为 init.d 生成单元):

# systemctl restart uwsgi
# systemctl restart nginx
# systemctl status uwsgi --no-pager -l | head -6
● uwsgi.service - LSB: Start/stop uWSGI server instance(s)
     Loaded: loaded (/etc/init.d/uwsgi; generated)
     Active: active (running) since Wed 2026-10-28 04:03:45 UTC; 29min ago
       Docs: man:systemd-sysv-generator(8)
    Process: 7361 ExecStart=/etc/init.d/uwsgi start (code=exited, status=0/SUCCESS)
      Tasks: 9 (limit: 2932)

uWSGI 按应用 ini 起了 1 master + 8 workers + 4 线程(/etc/uwsgi/apps-enabled/bounca.ini 定义),进程与 socket 核验:

# ls -l /run/uwsgi/app/bounca/
total 4
-rw-r--r-- 1 root     root 5 Oct 28 04:03 pid
srwx------ 1 www-data root 0 Oct 28 04:03 socket
# ps aux | grep -c "[u]wsgi"
10

4.10 部署验证

# curl -s -o /dev/null -w "front: %{http_code}\n" http://127.0.0.1/
front: 200
# curl -s -o /dev/null -w "admin: %{http_code}\n" http://127.0.0.1/admin/login/
admin: 200
# curl -s -o /dev/null -w "static: %{http_code}\n" http://127.0.0.1/static/admin/css/base.css
static: 200
# curl -s -o /dev/null -w "api: %{http_code}\n" http://127.0.0.1/api/
api: 200

首页 HTML(节选)确认为 BounCA 前端:

# curl -s http://127.0.0.1/ | head -c 220
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>BounCA PKI</title>

以管理员账号实测 API 登录(Web 界面登录走同一接口,账号 admin / 密码 q1w2e3r4):

# curl -s -X POST http://127.0.0.1/api/v1/auth/login/ -H "Content-Type: application/json" -d '{"username":"admin","password":"q1w2e3r4"}'
{"key":"adb2e74ad4eafb7f458e4c4358dced35fa17e871"}

返回 key 即会话 Token,部署完成。局域网内浏览器访问 http://10.89.70.10/ 进入 Web 界面,http://10.89.70.10/admin/ 进入管理后台。

五、安装方案 B:GitLab 源码仓

5.1 方案说明

适合需要跟进 master 开发版、自打补丁或二次开发的场景。与发行包方案的两点实质差异:

  1. 源码仓不含预构建前端(无 front/dist 产物),需自行执行仓内 build-front.sh(Node.js 构建 Vuetify 工程),构建链路复杂度显著上升;
  2. master 分支代码非定版,无 changelog 对应关系,不适合直接上生产。

5.2 实测拉取

# apt-get install -y git
# cd /tmp
# git clone --depth 1 https://gitlab.com/bounca/bounca.git bounca-src
Cloning into 'bounca-src'...
# ls bounca-src | head -8
CONTRIBUTING.md
LICENSE
Makefile
README.md
api
bounca
build-front.sh
build-package.sh

5.3 与发行包方案的衔接

源码目录结构与发行包解包结果一致(api/、bounca/、x509_pki/、certificate_engine/、etc/ 等),前端构建产物就位后(或仅使用 /admin 与 API、暂不启用 SPA 前端),后续步骤与 4.34.10 完全相同,把 4.14.2 的「下载解包」替换为「clone 到 /srv/www/bounca 并 chown www-data:www-data -R」即可。

六、方案对比选择建议

维度方案 A:官方发行包方案 B:源码仓
版本性质定版(changelog 可追溯,本篇 0.4.8)master 开发版,随时变动
前端产物预构建,解包即用需自建 Node.js 构建链
依赖版本requirements.txt 全锁定同文件锁定,但代码可能要求更新依赖
适用场景生产部署、常规运维补丁验证、二次开发、跟进修复
实测结论全流程通过(本文第四节)拉取验证通过,生产不建议

结论:生产与学习场景一律选方案 A;仅当需要修改源码时用方案 B 拉源码,改完仍建议走方案 A 的发行包基线做回归。

七、配置说明与验收清单

部署涉及的三份配置各自职责(逐参数语义、生效验证与改动实测集中在《BounCA 0.4.8 配置参数详解》):

文件职责关键项
/etc/bounca/services.yaml应用全部运行参数(六段:psql/django/admin/mail/certificate-engine/registration)数据库口令、secret_key、django.hosts 白名单
/etc/nginx/sites-available/bounca静态前端托管 + /api、/admin 反代 uWSGI socketserver_name、location /static 指向 /srv/www/bounca/media
/etc/uwsgi/apps-available/bounca.iniuWSGI 进程模型processes=8、chdir=/srv/www/bounca、home=/srv/www/bounca/env

验收清单(实测机全部通过):systemd 三单元 active、uWSGI socket 属主 www-data、四类端点 200(front/admin/static/api)、API 登录返回 Token、django_site 域名与访问地址一致。

八、常见问题(排障实录)

FAQ-1 venv 属主不符:Permission denied: '/srv/www/bounca/env/lib/python3.10/site-packages/...' 实测:以 root 执行 virtualenv env 后切 www-data 运行 pip install,报 ERROR: Could not install packages due to an OSError: [Errno 13] Permission denied: '/srv/www/bounca/env/lib/python3.10/site-packages/pytz'。修复:chown -R www-data:www-data /srv/www/bounca/env 后重装成功。规范做法是 venv 的创建、依赖安装、应用运行始终同一用户。

FAQ-2 services.yaml 缺段:ValueError: No 'psql' section found in services.yaml 实测:将 /etc/bounca/services.yaml 移走后执行 manage.py migrate,因只剩内置 .defaults(无 psql/mail/registration 段)而抛错。修复:恢复完整六段配置文件。配置加载顺序为「内置 defaults → 应用内 etc/bounca/services.yaml → /etc/bounca/services.yaml」,逐层覆盖。

FAQ-3 secret_key 未改:ValueError: Set an unique secret key in services.yaml 实测:将发行包自带 services.yaml.example 原样放到 /etc/bounca/services.yaml(secret_key 仍为占位串)启动即抛此错。修复:secret_key 必须替换为随机串(python3 -c "import secrets; print(secrets.token_urlsafe(48))")。

FAQ-4 重复执行建库:createuser: error: creation of new role failed: ERROR: role "bounca" already exists 实测:前次已建过角色时重跑 createuser 即报此错。修复:先 psql -c '\du' 核对角色与 \l 核对库,缺哪步补哪步;密码可随时用 ALTER USER ... WITH PASSWORD 重设(幂等)。

FAQ-5 uWSGI 起动成功但 502/no python application found 官方 README 点名原因:/var/log/bounca 不存在或属主非 www-data。处置:mkdir -p /var/log/bounca && chown -R www-data:www-data /var/log/bounca 后重启 uwsgi;日志落在 /var/log/uwsgi/bounca.log,先看日志再猜。

FAQ-6 静态资源 404 Nginx 模板中 location /static 的 root 是 /srv/www/bounca/media(不是 media/static),URL 需带上 app 前缀,例如 /static/admin/css/base.css、/static/grappelli/...;管理后台样式 404 通常是 collectstatic 没执行或 media/static 属主不对。

九、卸载清理

按产生物逆向清理(执行后用验证命令确认):

# systemctl stop uwsgi nginx
# rm -f /etc/nginx/sites-enabled/bounca /etc/nginx/sites-available/bounca
# rm -f /etc/uwsgi/apps-enabled/bounca.ini /etc/uwsgi/apps-available/bounca.ini
# rm -rf /srv/www/bounca /srv/www/bounca-0.4.8.tar.gz /var/log/bounca /etc/bounca
# su - postgres -c "dropdb bounca && dropuser bounca"
# apt-get purge -y uwsgi uwsgi-plugin-python3

验证:ls /srv/www、ls /etc/bounca 均为空/不存在;su - postgres -c "psql -c '\l'" 不再出现 bounca 库;dpkg -l | grep uwsgi 无输出。

十、参考链接

外部来源:

  1. 官方 README(v0.4.8 发行包,Debian/Ubuntu 安装章节)
  2. GitLab Packages 发行包:https://gitlab.com/bounca/bounca/-/packages
  3. 0.4.8 包文件直链(本文实测下载源):https://gitlab.com/bounca/bounca/-/package_files/267456786/download

本系列其他篇目: