Tandoor Recipes 手动部署指南:Django + Gunicorn + PostgreSQL + Nginx 全流程安装
2026/9/16 15:48:22 网站建设 项目流程

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.pyrecipes/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 nginx

3. 拉取代码并放置到 /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/recipes

4. 创建并激活 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-dev

LDAP 依赖对应 requirements.txt 中的python-ldapdjango-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_URLSTATIC_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_URLDB_ENGINE/POSTGRES_*两种配置方式。若未设置任何数据库变量,会退化为 SQLite(django.db.backends.sqlite3)。

三、初始化应用

1. 加载环境变量并执行迁移

# 将 .env 中非注释行的变量导入当前 shell(每行形如 KEY=VALUE) export $(cat /var/www/recipes/.env | grep "^[^#]" | xargs) # 执行数据库迁移 bin/python3 manage.py migrate

migrate会依据 cookbook/migrations 下从0001_initial.py0242_space_household_setup_completed.py的 240+ 个迁移文件创建全部数据表。

2. 收回数据库超级用户权限

sudo -u postgres psql
ALTER USER djangouser WITH NOSUPERUSER; exit

3. 收集静态文件

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_schemehttps,避免 Django 生成错误的协议链接。

这意味着在 Nginx 中额外配置proxy_set_header X-Forwarded-Proto $scheme;等头即可让应用正确感知真实协议与子路径。

2. Nginx 反向代理

创建 Nginx 站点配置:

sudo nano /etc/nginx/conf.d/recipes.conf
server { 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; } }

注意修正aliasproxy_pass中的实际路径。仓库的 nginx 参考配置(nginx/conf.d/Recipes.conf)也提供了带 TLS/HTTP2 的完整示例,可对照参考。

若将应用部署在子路径(如/recipes),结合上文recipes/wsgi.pyHTTP_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 或页面样式异常,通常就是静态文件未重新收集所致。

六、验证与排障要点

  1. 服务状态检查systemctl status gunicorn_recipes应显示active (running);异常时可查看/tmp/gunicorn_err.log
  2. 内存不足yarn buildReached heap limit时,确认可用内存 ≥ 2 GB,或考虑为 Node 显式提高堆上限。
  3. 数据库连不上:确认.envPOSTGRES_HOSTPOSTGRES_PORTPOSTGRES_USERPOSTGRES_PASSWORD与建库时一致;POSTGRES_PASSWORD缺失时应用会直接报错(boot.sh 中对这一必填项有明确校验与告警)。
  4. 静态资源 404:核对 Nginxlocation /static/alias是否指向collectstatic的实际输出目录(默认staticfiles/)。
  5. 权限问题/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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询