5.9 KiB
GymFlow Deployment Guide (NAS / Existing Container)
This guide explains how to deploy GymFlow to your Ugreen NAS by integrating it into your existing nodejs-apps container.
1. Preparation (Build)
You need to build the application on your local machine before transferring it to the NAS.
Build Frontend
Run the following in the project root:
npm install
npm install
npm run build
Important
If you encounter a
TypeError: Missing parameter namein your logs, ensure you have rebuilt the app with the latest changes (app.get('*all', ...)). This creates adistfolder with the compiled frontend.
Build Backend
- Update your
server/package.jsonto have these scripts for production:
"scripts": {
"start": "node dist/index.js",
"start:prod": "node dist/index.js",
...
}
- Run the following locally:
cd server
npm install
npm run build
cd ..
2. Transfer Files
Copy the entire gymflow folder to your NAS.
Destination: nodejs_data/gymflow (inside the folder mounted to /usr/src/app).
Ensure the following files/folders are present on the NAS:
gymflow/dist/(Frontend assets)gymflow/server/dist/(Backend code)gymflow/server/package.jsongymflow/server/prisma/(Schema for database)gymflow/ecosystem.config.cjs(PM2 config)
Note: You do not need to copy node_modules. We will install production dependencies on the NAS to ensure compatibility.
Update your docker-compose.yml to use a custom Dockerfile (to support building native modules like better-sqlite3) and map the new port.
2a. Use Custom Dockerfile
The standard node:lts-slim image lacks Python and build tools. Use the provided Dockerfile.node-apps:
- Copy
Dockerfile.node-appsto your NAS alongsidedocker-compose.yml. - Modify
docker-compose.yml:
services:
nodejs-apps:
build:
context: .
dockerfile: Dockerfile.node-apps
container_name: node-apps
# image: node:lts-slim <-- Comment this out
...
3. Integration
Update command
Add the following to your existing command string. We added npx prisma generate explicitly to ensure the Linux client is built correctly, and we ensure DATABASE_URL is consistent:
... && cd ../gymflow/server && npm install --omit=dev && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma generate && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma db push && cd .. && pm2 start ecosystem.config.cjs && ...
Note: We assume gymflow is a sibling of ag-beats etc.
Full Command Example:
command: /bin/sh -c "npm install -g pm2 && cd ag-beats && npm install && cd ../ball-shooting && npm install && cd ../gymflow/server && npm install --omit=dev && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma generate && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma db push && cd .. && pm2 start ecosystem.config.cjs && cd ../ag-beats && pm2 start ecosystem.config.js && cd ../ball-shooting && pm2 start npm --name ag-ball -- start && pm2 logs --raw"
Important
Since we updated the
Dockerfile.node-appsto includeopenssl(required by Prisma), you must rebuild the image:docker-compose up -d --build nodejs-apps
Update ports
Add the GymFlow port (3003 inside container, mapped to your choice, e.g., 3033):
ports:
- "3030:3000"
- "3031:3001"
- "3032:3002"
- "3033:3003" # GymFlow
4. Unified Ecosystem Config
Your common ecosystem.config.js should look like this to ensure GymFlow has the correct production environment:
module.exports = {
apps: [
{
name: "ag-home",
script: "server.js",
cwd: "/usr/src/app",
exec_mode: "fork",
},
{
name: "ag-beats",
script: "npm",
args: "start",
cwd: "/usr/src/app/ag-beats",
},
{
name: "ag-ball",
script: "npm",
args: "start",
cwd: "/usr/src/app/ball-shooting",
},
{
name: "gymflow",
script: "dist/index.js",
cwd: "/usr/src/app/gymflow/server",
env: {
NODE_ENV: "production",
APP_MODE: "prod",
PORT: 3003,
DATABASE_URL: "file:./prod.db",
DATABASE_URL_PROD: "file:./prod.db"
}
}
]
};
5. Nginx Proxy Manager
Point your domain (e.g., gym.yourdomain.com) to the NAS IP and the mapped port (3033).
- Scheme:
http - Forward Hostname / IP:
[NAS_IP] - Forward Port:
3033 - Websockets Support: Enable (if needed for future features).
6. Troubleshooting
"Readonly Database" Error
If you see an error like Invalid prisma.userProfile.upsert() invocation: attempt to write a readonly database:
-
Verify Permissions: Run the diagnostic script inside your container:
docker exec -it node-apps node /usr/src/app/gymflow/server/check_db_perms.js -
Fix Permissions: If the checks fail, run these commands on your NAS inside the
gymflow/serverdirectory:sudo chmod 777 . sudo chmod 666 prod.dbNote: SQLite needs write access to the directory itself to create temporary journaling files (
-wal,-shm). -
Check Docker User: Alternatively, ensure your Docker container is running as a user who owns these files (e.g., set
user: "1000:1000"indocker-compose.ymlif your NAS user has that ID).
"Invalid ELF Header" Error
If you see an error like invalid ELF header for better-sqlite3.node:
This happens because the node_modules contains Windows binaries (from your local machine) instead of Linux binaries.
- Fix Inside Container: Run the following command to force a rebuild of native modules for Linux:
docker exec -it node-apps /bin/sh -c "cd /usr/src/app/gymflow/server && npm rebuild better-sqlite3" - Restart Container: After rebuilding, restart the container:
docker-compose restart nodejs-apps