Tandoor Recipes 手动部署指南:Django + Gunicorn + PostgreSQL + Nginx 全流程安装
【免费下载链接】recipesApplication for managing recipes, planning meals, building shopping lists and much much more!项目地址: https://gitcode.com/GitHub_Trending/re/recipes
导读
本文基于仓库内 docs/install/manual.md 编写,完整讲解在 Ubuntu/Debian 类服务器上手动安装 Tandoor Recipes(recipes项目)的每一步:从系统依赖、Python 虚拟环境、Node.js 前端构建,到 PostgreSQL 数据库初始化、.env环境变量配置、Django 数据迁移,再到 Gunicorn + Nginx 的生产级 Web 服务编排与日常更新流程。读完本文,你将掌握一套不依赖 Docker 的裸机部署方案,并理解recipes/settings.py、recipes/wsgi.py、.env.template等关键文件背后的运行原理。
⚠️ 官方提示:本文所述流程属于"手动安装"路线,并非日常更新维护的文档,可能随时间过期。生产环境更推荐使用 Docker 部署;但手动部署能帮助你深入理解项目的运行机制。
部署架构总览
Tandoor Recipes 的技术栈在 requirements.txt 与 vue3/package.json 中有直接体现:
- 后端:Django 5.2(recipes/settings.py),通过
python-dotenv从.env文件加载配置; - WSGI 服务器:Gunicorn(
gunicorn==26.2.0); - 数据库:PostgreSQL(
psycopg2-binary),也支持 SQLite 兜底; - 前端:Vue 3 + Vite + Vuetify,构建产物位于
vue3目录,由django-vite集成进 Django; - 反向代理:Nginx,负责转发请求并托管静态/媒体文件;
- 静态文件:
whitenoise亦在依赖列表中,但在手动部署中主要由 Nginx 直接服务/static/与/media/。
整体请求链路为:Nginx(8002) → Gunicorn(unix socket) → Django(recipes.wsgi:application) → PostgreSQL。
一、安装前准备
1. 系统与硬件要求
官方在文档开篇给出了两条硬性警告:
- Python 版本必须 ≥ 3.12,并确认
pip与 Python 3 绑定。部分系统上python/pip可能默认指向 Python 2,导致依赖安装失败; - 机器内存至少 2048 MB,否则
yarn build可能因 JavaScript 堆内存不足而失败,报错:FATAL ERROR: Reached heap limit - Allocation failed: JavaScript heap out of memory。
前端构建是内存大户(Vite 打包 Vue3 + Vuetify),低配 VPS 上尤其需要留意。
2. 创建运行用户与系统依赖
# 创建专用运行用户(Gunicorn 将以该用户身份运行) sudo useradd recipes # 更新软件源并升级系统 sudo apt update && sudo apt upgrade -y # 安装基础依赖 sudo apt install -y git curl python3 python3-pip python3-venv nginx3. 拉取代码并放置到 /var/www
# 克隆仓库(master 分支为最新稳定版) git clone https://github.com/vabene1111/recipes.git -b master # 移动到 Web 目录 mv recipes /var/www # 进入项目目录 cd /var/www/recipes # 赋予运行用户与 Web 用户组权限 chown -R recipes:www-data /var/www/recipes4. 创建并激活 Python 虚拟环境
文档示例为:
python3 -m venv /var/www/recipes source /var/www/recipes/bin/activate实践建议:
/var/www/recipes同时是项目源码目录,直接把 venv 建在项目根目录可能与源码文件混在一起。仓库容器入口脚本 boot.sh 使用的是项目内独立目录venv/(见source venv/bin/activate)。更稳妥的做法是在项目内单独建venv目录,并将后文所有/var/www/recipes/bin/xxx路径相应改为/var/www/recipes/venv/bin/xxx,避免虚拟环境与源码目录冲突。以下命令仍按官方文档原样给出。
5. 安装 JavaScript 工具链(Node.js ≥ 12 与 Yarn)
官方文档提供了多发行版安装方式,任选其一:
# Ubuntu:使用 nodesource 的 LTS 源 curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt install -y nodejs # Debian(root 用户) curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - apt install -y nodejs # RPM 系发行版 # ... 以 root 执行 curl -fsSL https://rpm.nodesource.com/setup_lts.x | bash - # ... 无 root 权限时 curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -随后全局安装 Yarn:
sudo npm install --global yarn若 Node.js 安装遇到问题,请参考 nodesource distributions 仓库的官方 README 排查(文档链接见 docs/install/manual.md 原文)。
提示:文档撰写时要求 Node.js ≥ 12,而当前仓库前端已升级为 Vite 8 + TypeScript 5.8(见 vue3/package.json 的 devDependencies),建议使用各发行版当前较新的 LTS 版本以兼容构建工具链。
6. 安装 PostgreSQL 与 LDAP 依赖
# PostgreSQL 驱动与数据库本体 sudo apt install -y libpq-dev postgresql # LDAP 认证所需依赖(若使用 LDAP 登录则需要) sudo apt install -y libsasl2-dev python3-dev libldap2-dev libssl-devLDAP 依赖对应 requirements.txt 中的python-ldap、django-auth-ldap,仅在使用企业目录认证时才真正生效;不需要 LDAP 可跳过。
7. 安装项目 Python 依赖
/var/www/recipes/bin/pip3 install -r requirements.txt⚠️ 依赖会随版本更新而变化,每次升级后都必须重跑本步骤,否则应用可能无法正常工作(见文末"更新"章节)。
8. 构建前端资源
进入vue3目录安装并构建前端:
cd ./vue3 yarn install yarn build构建产物通过django-vite与 Django 集成:recipes/settings.py 中的DJANGO_VITE配置指向cookbook/static/vue3/manifest.json,生产模式下dev_mode固定为False,Django 直接依据 manifest 加载打包后的 JS/CSS。
二、配置 PostgreSQL 数据库
1. 创建数据库与用户
进入 PostgreSQL 控制台:
sudo -u postgres psql在 psql 中执行:
CREATE DATABASE djangodb; CREATE USER djangouser WITH PASSWORD 'password'; GRANT ALL PRIVILEGES ON DATABASE djangodb TO djangouser; ALTER DATABASE djangodb OWNER TO djangouser; -- 以下三项非必需,但通常能提升性能与一致性 ALTER ROLE djangouser SET client_encoding TO 'utf8'; ALTER ROLE djangouser SET default_transaction_isolation TO 'read committed'; ALTER ROLE djangouser SET timezone TO 'UTC'; -- 临时授予超级用户权限(用于后续数据库初始化),迁移完成后会收回 ALTER USER djangouser WITH SUPERUSER; -- 退出 psql exit文档特别提示:djangouser被临时授予 SUPERUSER,是为了保证manage.py migrate阶段能顺利建表;初始化完成后务必撤销(见下文"初始化应用"一节)。
2. 下载并编辑 .env 配置文件
wget https://raw.githubusercontent.com/vabene1111/recipes/develop/.env.template -O /var/www/recipes/.env仓库根目录自带同款模板 .env.template,内容如下(当前仓库版本):
# 随机密钥,可用 `base64 /dev/urandom | head -c50` 生成 SECRET_KEY= # 默认时区,参见时区数据库 TZ=Europe/Berlin # 允许访问的主机名(必须设置为你的域名/IP) ALLOWED_HOSTS=recipes.mydomain.com # 仅在使用默认 PostgreSQL 时需要配置数据库密码,否则请相应修改 DB_ENGINE=django.db.backends.postgresql POSTGRES_HOST=db_recipes POSTGRES_DB=djangodb POSTGRES_PORT=5432 POSTGRES_USER=djangouser POSTGRES_PASSWORD=按官方文档,手动部署需重点修改的项:
SECRET_KEY:使用安全随机值,例如base64 /dev/urandom | head -c50生成;POSTGRES_HOST:本机数据库通常填127.0.0.1;POSTGRES_PASSWORD:填写上文建库时设置的密码;STATIC_URL/MEDIA_URL:分别指向/var/www/recipes下的/staticfiles/与/mediafiles/。
从源码角度理解这些变量的作用(见 recipes/settings.py):
- 第 45-46 行:
STATIC_URL与STATIC_ROOT均从环境变量读取,STATIC_ROOT默认BASE_DIR/staticfiles,正是collectstatic的输出目录; - 第 49 行:
SECRET_KEY有默认值INSECURE_STANDARD_KEY_SET_IN_ENV,仅用于开发,生产环境必须覆盖; - 第 125 行:
ALLOWED_HOSTS通过extract_comma_list('ALLOWED_HOSTS', '')解析,支持逗号分隔多个主机名; - 第 475-543 行:
setup_database()函数统一处理DATABASE_URL与DB_ENGINE/POSTGRES_*两种配置方式。若未设置任何数据库变量,会退化为 SQLite(django.db.backends.sqlite3)。
三、初始化应用
1. 加载环境变量并执行迁移
# 将 .env 中非注释行的变量导入当前 shell(每行形如 KEY=VALUE) export $(cat /var/www/recipes/.env | grep "^[^#]" | xargs) # 执行数据库迁移 bin/python3 manage.py migratemigrate会依据 cookbook/migrations 下从0001_initial.py到0242_space_household_setup_completed.py的 240+ 个迁移文件创建全部数据表。
2. 收回数据库超级用户权限
sudo -u postgres psqlALTER USER djangouser WITH NOSUPERUSER; exit3. 收集静态文件
bin/python3 manage.py collectstatic --no-input bin/python3 manage.py collectstatic_js_reverse注意记住静态文件被复制到的目录(默认即BASE_DIR/staticfiles,对应.env中的STATIC_URL),Nginx 配置需要引用它。collectstatic_js_reverse用于生成 JavaScript 可用的 URL 反向解析文件,是 Tandoor 自有的辅助命令。
四、配置 Web 服务
1. Gunicorn systemd 服务
创建服务文件:
sudo nano /etc/systemd/system/gunicorn_recipes.service内容如下:
[Unit] Description=gunicorn daemon for recipes After=network.target [Service] Type=simple Restart=always RestartSec=3 User=recipes Group=www-data WorkingDirectory=/var/www/recipes EnvironmentFile=/var/www/recipes/.env ExecStart=/var/www/recipes/bin/gunicorn --error-logfile /tmp/gunicorn_err.log --log-level debug --capture-output --bind unix:/var/www/recipes/recipes.sock recipes.wsgi:application [Install] WantedBy=multi-user.target两点说明:
--error-logfile /tmp/gunicorn_err.log --log-level debug --capture-output仅用于排查问题,稳定运行后可移除;- 按实际安装位置修正
ExecStart中 gunicorn 与项目目录的路径。
启动并检查服务:
sudo systemctl enable --now gunicorn_recipes systemctl status gunicorn_recipes从源码看,recipes.wsgi:application并非普通的 Django WSGI 应用——recipes/wsgi.py 在标准get_wsgi_application()之外包了一层中间件:
- 读取
HTTP_X_SCRIPT_NAME请求头,支持把应用部署在子路径(如/recipes)下; - 读取
HTTP_X_SCHEME请求头,代理场景下保证wsgi.url_scheme为https,避免 Django 生成错误的协议链接。
这意味着在 Nginx 中额外配置proxy_set_header X-Forwarded-Proto $scheme;等头即可让应用正确感知真实协议与子路径。
2. Nginx 反向代理
创建 Nginx 站点配置:
sudo nano /etc/nginx/conf.d/recipes.confserver { listen 8002; #access_log /var/log/nginx/access.log; #error_log /var/log/nginx/error.log; # 服务静态文件 location /static/ { alias /var/www/recipes/staticfiles/; } location /media/ { alias /var/www/recipes/mediafiles/; } location / { proxy_set_header Host $http_host; proxy_pass http://unix:/var/www/recipes/recipes.sock; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; } }注意修正alias与proxy_pass中的实际路径。仓库的 nginx 参考配置(nginx/conf.d/Recipes.conf)也提供了带 TLS/HTTP2 的完整示例,可对照参考。
若将应用部署在子路径(如
/recipes),结合上文recipes/wsgi.py对HTTP_X_SCRIPT_NAME的支持,还需要在location /recipes/中设置proxy_set_header X-Script-Name /recipes;,并相应配置SCRIPT_NAME环境变量(见 recipes/settings.py 第 42-43 行)。
重新加载 Nginx:
sudo systemctl reload nginx至此,通过http://服务器IP:8002即可访问应用。
五、应用更新流程
依赖会随更新变化,因此每次升级需要完整重跑一遍构建与迁移。官方建议将以下命令放入一个小脚本:
# 进入项目目录 cd /var/www/recipes # 拉取最新源码 git pull # 重新加载环境变量 export $(cat /var/www/recipes/.env | grep "^[^#]" | xargs) # 重新安装 Python 依赖 bin/pip3 install -r requirements.txt # 执行数据库迁移 bin/python3 manage.py migrate # 收集静态文件 # 若输出不是 "0 static files copied",建议再执行一次以确保全部收集 bin/python3 manage.py collectstatic --no-input bin/python3 manage.py collectstatic_js_reverse # 进入前端目录并重建 cd vue3 yarn install yarn build # 重启 Gunicorn 服务 sudo systemctl restart gunicorn_recipes该流程与容器版入口脚本 boot.sh 的执行顺序一致(migrate → collectstatic → gunicorn),只是容器场景由启动脚本自动完成。每次git pull后若出现 JS/CSS 资源 404 或页面样式异常,通常就是静态文件未重新收集所致。
六、验证与排障要点
- 服务状态检查:
systemctl status gunicorn_recipes应显示active (running);异常时可查看/tmp/gunicorn_err.log。 - 内存不足:
yarn build报Reached heap limit时,确认可用内存 ≥ 2 GB,或考虑为 Node 显式提高堆上限。 - 数据库连不上:确认
.env中POSTGRES_HOST、POSTGRES_PORT、POSTGRES_USER、POSTGRES_PASSWORD与建库时一致;POSTGRES_PASSWORD缺失时应用会直接报错(boot.sh 中对这一必填项有明确校验与告警)。 - 静态资源 404:核对 Nginx
location /static/的alias是否指向collectstatic的实际输出目录(默认staticfiles/)。 - 权限问题:
/var/www/recipes需归属recipes:www-data,否则 Gunicorn 可能无法读写媒体文件或 socket。
小结
本文完整复现了官方手动安装文档的全部步骤,并补充了仓库源码层的依据:.env各变量在 recipes/settings.py 中的解析逻辑、recipes/wsgi.py对反向代理/子路径的支持、前端构建与django-vite的集成方式,以及容器启动脚本 boot.sh 中可对照的初始化顺序。这套 Django + Gunicorn + PostgreSQL + Nginx 方案不依赖 Docker,适合对传统 Linux 运维栈熟悉、或需要在受限环境中自管服务的场景;若追求一键部署与自动升级,仍建议优先参考 Docker 安装指南。
【免费下载链接】recipesApplication for managing recipes, planning meals, building shopping lists and much much more!项目地址: https://gitcode.com/GitHub_Trending/re/recipes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考