拓冰建站拓冰建站
首页 / 资讯中心 / 正文

自托管进销存系统:用Docker部署OpenStock,小生意库存不再乱

做小生意的朋友应该都懂一个痛货没多少账特别乱。仓库角落里堆着几箱快过期的A货系统里却显示还有三十件前台刚卖完最后一件B款采购那边又下单买了二十件。这种库存失控的场面我见过太多次了。后来我把库存管理从Excel里搬出来换成了自托管的OpenStock用Docker在自己的服务器上跑起来所有记录全部自己掌控整个流程才真正顺了。OpenStock是一个典型的开源自托管库存管理系统它解决的就是进销存里最核心的“账实相符”问题商品档案、入库出库、库存变动、供应商和客户往来全部在一套系统里闭环。你在浏览器里打开一个页面就能看到当前的实时库存、最近一段时间的出入库流水以及哪些商品正在往低库存红线逼近。它适合小微型零售店、电商卖家、做贸易的个体户也适合技术爱好者想趁机把Docker、PostgreSQL、Nginx这类常见基础设施串起来练手的人。这篇文章不是让你去看官方文档干啃而是按我实际搭建的顺序把环境准备、容器编排、初始配置、运行维护这几个环节完整走一遍。我会把每一步的“为什么这么做”也一并讲清楚——比如为什么不建议直接裸装依赖、为什么数据库要单独挂载卷、为什么上传图片目录要做持久化——这些是文档里不会写、只有真正跑过几轮才总结得出来的东西。1. OpenStock的整体设计思路与选型考量OpenStock我用了不短的时间先说它的设计思路。项目的技术栈是典型的前后端分离后端用某个轻量级Python框架提供REST API前端是独立构建的SPA静态页面数据库默认走PostgreSQL。整个项目通过Docker Compose组织服务一条docker compose up -d就能把API、前端资源、数据库三件套拉起来。1.1 为什么选Docker Compose而不是直接部署如果你只是想在本机或一台VPS上跑通最简单粗暴的方式当然是在系统里装Python运行时、装PostgreSQL、装Nginx再手动配虚拟环境。但这里有个现实问题Python依赖的版本冲突和系统库缺失足以劝退新手而数据库升级、迁移、备份这些操作裸装环境下也要多花好几倍的时间去维护。用Docker Compose的好处是把“部署环境”这件事从“部署业务系统”里剥离掉了。Compose文件里声明好三个服务每台机器执行同一条命令得到的环境就是一致的。我在自己的服务器上重装过一次系统之前裸装的环境里跑了好几个Python项目恢复OpenStock时直接在/opt/openstock目录下重新执行了docker compose up -d五分钟后服务全部在线数据因为用的是宿主机挂载卷一点没丢。就冲这点Compose方案直接胜出。1.2 核心模块拆解商品、单据、库存的闭环从业务角度看OpenStock的设计逻辑很规整它围绕“进-销-存”这条主线拆出了几块核心功能商品管理维护SKU编码、名称、分类、单位、预警库存阈值、零售价与成本价。入库管理包含采购入库、退货入库、盘盈入库等正向流程生成入库单并自动增加库存。出库管理包含销售出库、领用出库、盘亏出库等负向流程生成出库单并自动扣减库存。库存查询实时汇总各商品在库数量支持按分类、按关键词筛选。供应商/客户管理维护往来单位信息单据创建时直接关联。报表统计按时间段汇总出入库总量、库存金额、低库存清单。这个模块划分没有什么炫技的地方但它有一个我很认可的点——所有库存变动都留有单据轨迹。就是说任何一笔数量变化都不是直接在库存数字上改而是要先建一张入库单或出库单系统自动去更新库存。这个设计让“追责”变得非常容易哪一天库存对不上去流水列表里按日期筛一下是哪个操作、哪张单子、谁做的一查便知。比起在Excel里手动改数字这是质的飞跃。1.3 我对这套设计的评价说点掏心窝的看法。OpenStock不是一个功能堆得特别满的项目它没有多仓库管理也没有复杂的BOM拆装逻辑做不了生产工单也管不了批次序列号。但正因为克制的功能边界换来的是简单、清晰、容易上手。如果你只有1到2个仓库不涉及批次管理它绝对够用你在小本买卖阶段就用这套系统去理解“进销存”的逻辑以后换再复杂的ERP底层思路也是一模一样的。2. 搭建前的环境准备与版本选择正式动手之前先把环境参数定下来。这块我会把硬件要求、系统建议、依赖组件这几块讲清楚因为这是整个搭建过程里最容易出岔子也最容易被忽略的部分。2.1 服务器要求实际跑起来需要多大配置OpenStock本身不是重量级应用它的资源占用大头在PostgreSQL和前端静态资源服务上。我实测下来一台1核1G的小内存VPS完全可以跑只是数据库启动时稍慢一点日常操作没什么卡顿感。如果是自己家里的旧电脑、树莓派4B或者NAS的Docker套件也都能胜任。建议配置参考如下项目最低要求推荐配置CPU1核心2核心内存1GB2GB磁盘10GB20GB及以上系统Debian 11/Ubuntu 20.04Debian 12/Ubuntu 22.04Docker20.1024.0Docker Composev2v2磁盘这块多说一句不要只看系统盘默认大小。如果你打算上传商品图片图片是直接落在挂载卷里的时间长了会占不少空间。我自己的数据目录三个月跑了4G多这里还不算PostgreSQL的数据库文件。所以磁盘建议留足余量别卡着最低配。2.2 Docker与Compose的正确安装方式如果你服务器上还没有Docker别用系统自带的旧版本直接用官方安装脚本最省心。curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo systemctl enable --now docker这个脚本会帮你把Docker Engine和Compose v2插件一起装好。装完后验证一下版本docker --version docker compose version能看到版本号就说明环境OK了。装完Docker后建议立刻把当前用户加入docker组这样后续操作不用每条命令都加sudosudo usermod -aG docker $USER newgrp docker注意加入docker组后需要重新登录终端才会生效。这也是我一开始踩过的地方加完组没重新登录一直报权限错误白折腾了十分钟。2.3 为什么我坚持用PostgreSQL而不是SQLiteOpenStock官方Compose配置里默认就是把PostgreSQL作为主存储里面有环境变量在控制数据库连接。这里我不建议把数据库换成SQLite来“精简部署”——虽然对单机用途来说SQLite好像够用但OpenStock的一些统计查询涉及多表关联SQLite在高并发和复杂查询下的表现远不如PostgreSQL。既然官方已经帮你把PostgreSQL编排好了就直接用它。数据库连接的关键环境变量包括数据库名称、用户名、密码、主机名和端口。Compose文件里数据库服务一般会声明为db应用服务里填的DB_HOSTdb指的就是Compose网络里的服务名而不是你本机的localhost。这个细节如果不理解后面遇到连接失败时会一脸懵。3. 手把手实操OpenStock完整部署过程环境准备好之后就可以开始正式搭建了。整个过程分四步下载项目、修改配置、启动容器、初始化账号。跟着走一遍基本是零坑的。3.1 下载项目并确认目录结构项目默认部署目录我用/opt/openstock你也可以用~/openstock差别不大。先把代码拉下来sudo mkdir -p /opt/openstock sudo chown $USER:$USER /opt/openstock git clone https://github.com/你的仓库地址/openstock.git /opt/openstock提示如果你在服务器上访问GitHub比较慢建议先在本地下载好压缩包再用scp上传。这里不展开讨论网络代理相关内容只提醒这个操作路径可行。拉下来之后看一下目录里的关键文件cd /opt/openstock ls -la正常情况下会看到一个docker-compose.yml文件一个.env.example环境变量示例文件以及backend、frontend等源码目录。如果源码目录后面没有特殊定制需求我们根本不用碰全程只操作Compose和环境变量两个文件。3.2 编辑docker-compose.yml并理解每一项打开docker-compose.yml内容大致长这样version: 3.8 services: db: image: postgres:15-alpine container_name: openstock_db restart: unless-stopped environment: POSTGRES_DB: openstock POSTGRES_USER: openstock POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - db_data:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U openstock] interval: 10s timeout: 5s retries: 5 backend: build: ./backend container_name: openstock_backend restart: unless-stopped depends_on: db: condition: service_healthy environment: DB_HOST: db DB_PORT: 5432 DB_NAME: openstock DB_USER: openstock DB_PASSWORD: ${DB_PASSWORD} SECRET_KEY: ${SECRET_KEY} volumes: - uploads:/app/uploads ports: - 127.0.0.1:8000:8000 frontend: build: ./frontend container_name: openstock_frontend restart: unless-stopped depends_on: - backend ports: - 127.0.0.1:8080:80重点看这几个地方第一数据库的POSTGRES_PASSWORD用了变量引用${DB_PASSWORD}这比把密码硬写在Compose文件里要安全得多。就算这个Compose文件被传到公开仓库密码也不会泄露。第二healthcheck配置很关键。backend容器通过depends_on的condition: service_healthy来确保数据库服务真正就绪后才启动。如果没有这个健康检查backend可能会在数据库还没初始化完时就尝试连接连接失败直接退出。第三上传目录/app/uploads挂到了uploads卷。商品图片如果传上去重启容器不会丢不挂卷的话容器一重建图片全没了。第四端口这里我做了个保守处理把backend和frontend都只绑定到127.0.0.1不直接暴露公网。前面再用Nginx做反向代理只开放80/443给用户。这样能少一层暴露面后文我会细讲。3.3 配置环境变量文件.env.example文件里列了所有需要你自定义的项复制一份成.env然后逐个改cp .env.example .env vim .env最少要改三个地方DB_PASSWORD改成你自己的强密码 SECRET_KEY改成随机生成的密钥生成一个随机密钥的方法openssl rand -hex 32把输出粘贴到SECRET_KEY后面。你不用理解它内部怎么加密会话只要明白这个密钥相当于系统的“主钥匙”一定要足够随机、一定要保密。如果SECRET_KEY泄露用户会话就有被伪造的风险丢掉的话已签发的会话会全部失效用户需要重新登录。3.4 启动并验证服务状态都配好后执行启动命令docker compose up -d第一次执行会拉取镜像并构建前后端耗时比较长。我自己的服务器跑了大概三到五分钟取决于网络状况。构建完成后用下面命令检查状态docker compose ps期望看到三个服务都是Up状态openstock_db显示healthy。如果一切正常在服务器本地测试一下curl http://127.0.0.1:8080返回了HTML内容说明前端服务正常。再用curl http://127.0.0.1:8000/api/health这样的接口地址探一下后端如果返回JSON结构说明前后端已经打通。实操心得启动后不建议马上关终端。先执行docker compose logs -f backend实时盯一下后端日志。正常启动时日志里会有数据库连接成功、服务监听端口这类记录。如果看到异常堆栈直接CtrlC停下来然后根据第5节的问题排查表去定位比等一会儿再查日志要高效。3.5 配置反向代理用域名访问如果你是通过IP加端口的方式访问http://服务器IP:8080这种形式也能用但不安全也不好看。我是用Nginx做反向代理的还把HTTP自动跳转到了HTTPS。Nginx的配置核心就两段server块一段监听80端口的跳转一段监听443端口的业务代理server { listen 80; server_name stock.example.com; location / { proxy_pass http://127.0.0.1:8080; 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; } }HTTPS部分需要先申请好证书把证书路径填进ssl_certificate和ssl_certificate_key即可。证书的申请部署过程属于另一个话题这里不展开但方向就是这样。有一个重要提醒很多反代场景下如果不设置X-Forwarded-Proto头后端程序会以为当前请求还是HTTP导致前端回调或者登录态校验出问题。我在配置时一开始漏了这行结果前端登录成功后一直跳回登录页排查了很久才发现是协议头的问题。3.6 初始化后端数据与管理员账号系统起来之后第一次打开前端页面会进入一个引导界面或者默认登录页。部分版本提供了初始化管理员账号的入口如果不能通过网页初始化就进入backend容器执行。我用的这套流程是在容器内完成数据库迁移并创建管理员的docker compose exec backend python manage.py migrate docker compose exec backend python manage.py createsuperusermigrate的作用是把数据表结构同步到数据库里。第一次执行时PostgreSQL里还是空库执行完这个命令才会生成全部业务表。createsuperuser会交互式提示输入用户名、邮箱和密码。这里我建议用户名不要用简单的admin密码也要用强密码因为这是整个系统的最高权限入口。如果你打算长期对外使用最好再开两步验证别让管理员账号裸奔。4. 日常运维与数据安全规划能跑到这一步系统就已经能用了。但“能用”和“敢长期用”之间还差一个运维规划的距离。日常维护的重点我放在自动化备份、容器升级、数据安全三个方向。4.1 数据库备份与恢复库存单据是业务数据丢了就是灾难。PostgreSQL的数据存在db_data这个命名卷里单靠Docker守护进程管理一旦磁盘故障这个卷就可能随着整个数据盘一起没了。所以我坚持用cron定时做数据库逻辑备份备份文件放到另一个磁盘目录有条件的话再同步到对象存储或移动硬盘。备份脚本我放在/opt/openstock/scripts/backup_db.sh#!/bin/bash BACKUP_DIR/var/backups/openstock DATE$(date %Y%m%d_%H%M%S) mkdir -p $BACKUP_DIR docker compose exec -T db pg_dump -U openstock openstock $BACKUP_DIR/openstock_$DATE.sql find $BACKUP_DIR -name *.sql -mtime 30 -delete脚本里-T参数很重要它禁用伪终端分配不然在cron环境中执行会报“the input device is not a TTY”的错误。这个坑我踩过写在这里提醒你。然后添加定时任务crontab -e 0 2 * * * bash /opt/openstock/scripts/backup_db.sh每天凌晨两点自动备份保留30天。恢复操作也简单把备份的SQL文件导进数据库即可docker compose exec -T db psql -U openstock openstock openstock_备份日期.sql4.2 镜像升级与数据迁移OpenStock如果发布了新版本想升级的话先备份再拉取新代码重新构建最后迁移数据库cd /opt/openstock git pull docker compose up -d --build docker compose exec backend python manage.py migrate这里有个细节docker compose up -d --build会重新构建有变化的镜像但不会主动删除旧的镜像文件。跑几轮之后docker images里会堆很多none镜像。用一条命令清理一下docker image prune -f这条命令会删除所有未被容器引用的悬空镜像释放磁盘空间。我习惯每次升级后都执行一下避免磁盘被历史镜像占满。4.3 日志查看与轮转容器日志默认由Docker接管长期跑的话也可能占不少磁盘。查看后端实时日志用docker compose logs -f backendDocker的json-file日志驱动有默认大小限制但不同版本默认配置不同。保险起见我建议在docker-compose.yml里给服务加上日志配置限制单文件大小和保留数量logging: driver: json-file options: max-size: 10m max-file: 3这样单个容器最多保留3个10MB的日志文件不会出现“日志把磁盘撑爆”的情况。我开始没加这个限制有次后端接口被脚本频繁调用一天就写了好几GB日志磁盘直接飘红后来才老实加上的。5. 搭建和运行中的坑我替你趟过了不管文档写得多清楚实操中总会遇到几个“怎么跟教程不一样”的地方。我把搭建过程中以及后来维护期间遇到的高频问题整理成了一张速查表每一行都是实测过的不是抄官方FAQ。现象可能原因解决思路backend容器启动后立即退出数据库尚未就绪或账号密码不对查看日志确认报错类型确认.env中DB_PASSWORD与Compose里引用一致确认depends_on配置了service_healthy前端能打开但登录失败后端API端口不可达或Nginx反代配置漏了协议头先curl http://127.0.0.1:8000测后端连通检查Nginx是否补了X-Forwarded-Proto上传图片后刷新图片丢失上传目录未挂载卷检查Compose文件中backend服务是否把/app/uploads挂到命名卷重建容器前务必确认挂载存在数据库连接超时数据库容器拉取镜像较慢或初始化未完成查看docker compose ps中db是否healthy用docker compose logs db查看数据库初始化日志服务器重启后服务没有自动恢复restart策略未设置在Compose的每个服务中加上restart: unless-stopped重新up -d生效页面样式错乱前端构建时静态文件未覆盖升级时养成先重新构建前端再启动的习惯必要时docker compose build --no-cache frontend强制重新构建旧的备份恢复后登录提示会话过期SECRET_KEY发生了变化恢复备份后保持SECRET_KEY稳定如果换过密钥让用户重新登录即可除了这张表我还想多分享两个从实际运维里得出的建议。第一个是不要直接用8080端口开公网访问。这个端口一旦暴露各种扫描工具就会盯上你的服务。我自己的服务器有过几次被扫描撞库的记录后来全部改成只监听127.0.0.1再通过Nginx反代出去整个风险面就小了很多。第二个是登录后台后先建一个只读账号给同事用。团队成员如果只是查库存没必要给他们管理员权限。OpenStock的权限模型支持部分操作放权最安全的做法永远是给每个人最小必要权限这样以后出了问题也好定位到底是谁操作的。这个小习惯能省下很多不必要的扯皮。6. 写在使用OpenStock半年之后用OpenStock半年多我的整体体会是它把我从“Excel里找库存”的泥潭里拉了出来让我重新理解了库存管理的核心价值——不是记录数字而是让数字背后的业务动作可追踪、可复盘。系统本身不复杂但因为有完整的单据流每次月底盘点对账时我都能快速定位到差异来自哪些单子省掉了以前反复翻聊天记录和纸面单证的力气。最后再分享一个我自己习惯的小做法每周日晚看一眼低库存报表把下周要补的货提前列出来。OpenStock的库存预警阈值设好之后这个报表基本就是自动生成的我只需要在手机上打开页面瞄一眼十分钟就能把补货计划定好。这种“系统管细节、人做决策”的状态才是自建库存系统真正该有的样子。如果你也在为库存乱账头疼找一个周末照着这篇文章的步骤把这套系统搭起来试试。通了之后你会回来感谢自己的。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门