From 5b02a13cb41c1d007851b3c09897504bcd899725 Mon Sep 17 00:00:00 2001 From: Bangara Raju Kottedi Date: Wed, 28 Jan 2026 14:02:27 +0530 Subject: [PATCH] ludo web based game config file changes --- .env | 8 + .gitignore | 2 +- Dockerfile | 116 +++++++- backend/config/database.js | 20 +- backend/server.js | 30 +- docker-compose.yml | 42 +++ src/App.js | 4 +- troubleshooting.md | 562 +++++++++++++++++++++++++++++++++++++ 8 files changed, 745 insertions(+), 39 deletions(-) create mode 100644 .env create mode 100644 docker-compose.yml create mode 100644 troubleshooting.md diff --git a/.env b/.env new file mode 100644 index 0000000..6395606 --- /dev/null +++ b/.env @@ -0,0 +1,8 @@ +# MongoDB connection for backend +CONNECTION_URI=mongodb://admin:adminpassword@mongo:27017/ludo?authSource=admin&replicaSet=rs0 + +# Backend port +PORT=18081 + +# Environment +NODE_ENV=production diff --git a/.gitignore b/.gitignore index 2e01d74..97c1520 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,4 @@ build npm-debug.log* yarn-debug.log* yarn-error.log* -.env \ No newline at end of file +# .env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8c665bc..cb1ab41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,111 @@ -FROM node:14 as frontend +# FROM node:14 as frontend +# WORKDIR /app +# COPY . /app +# RUN npm install --production +# RUN npm run build + +# FROM node:14 as backend +# WORKDIR /app +# COPY /backend /app +# RUN npm install + +# FROM node:14 +# WORKDIR /app +# COPY --from=backend /app /app/ +# COPY --from=frontend /app/build /app/build + +# EXPOSE 8080 + +# CMD ["npm", "run", "start"] + + +const express = require('express'); +const cors = require('cors'); +const path = require('path'); +const cookieParser = require('cookie-parser'); +const mongoose = require('mongoose'); +require('dotenv').config(); +const { sessionMiddleware } = require('./config/session'); + +const PORT = process.env.PORT || 5000; + +const app = express(); + +app.use(cookieParser()); +app.use(express.urlencoded({ extended: true })); +app.use(express.json()); +app.set('trust proxy', 1); + +/* ---------- CORS ---------- */ +app.use( + cors({ + origin: + process.env.NODE_ENV === 'production' + ? true // same origin (Docker / prod) + : 'http://localhost:3000', + credentials: true, + }) +); + +app.use(sessionMiddleware); + +const server = app.listen(PORT, "0.0.0.0", () => { + console.log(`Server listening on port ${PORT}`); +}); + +/* ---------- Mongo + Socket ---------- */ +require('./config/database')(mongoose); +require('./config/socket')(server); + +/* ---------- Serve React build ---------- */ +if (process.env.NODE_ENV === 'production') { + const buildPath = path.resolve(__dirname, 'build'); + + app.use(express.static(buildPath)); + + app.get('*', (req, res) => { + res.sendFile(path.join(buildPath, 'index.html')); + }); +} + +module.exports = { server }; +root@DietPi:~/mern-ludo/backend# ^C +root@DietPi:~/mern-ludo/backend# cd . +root@DietPi:~/mern-ludo/backend# cd .. +root@DietPi:~/mern-ludo# nano Dockerfile +root@DietPi:~/mern-ludo# cat Dockerfile +# Node 20 for Pi 5 (ARM64) +FROM node:20-bullseye-slim + WORKDIR /app + +# Copy all files COPY . /app -RUN npm install --production + +# Install frontend (root) dependencies +RUN npm install --legacy-peer-deps + +# Build frontend RUN npm run build -FROM node:14 as backend -WORKDIR /app -COPY /backend /app -RUN npm install +# Install backend dependencies +RUN cd backend && npm install --production --legacy-peer-deps -FROM node:14 -WORKDIR /app -COPY --from=backend /app /app/ -COPY --from=frontend /app/build /app/build +# Move frontend build into backend/public for Express +# RUN cp -r build backend/public +RUN rm -rf backend/build +RUN cp -r build backend/build -EXPOSE 8080 +# Copy wait-for-mongo.sh and make it executable +COPY wait-for-mongo.sh ./ +RUN chmod +x wait-for-mongo.sh -CMD ["npm", "run", "start"] +# Default fallback values (can be overridden by Compose) +ENV NODE_ENV=production +ENV PORT=8080 +ENV CONNECTION_URI=mongodb://mongo:27017/ludo?replicaSet=rs0 + +EXPOSE 18081 + +# Start backend with wait-for-mongo +CMD ["bash", "./wait-for-mongo.sh", "mongo", "27017", "node", "backend/server.js"] diff --git a/backend/config/database.js b/backend/config/database.js index f347966..4d5542f 100644 --- a/backend/config/database.js +++ b/backend/config/database.js @@ -1,13 +1,9 @@ -module.exports = function (mongoose) { - mongoose.set('useFindAndModify', false); - mongoose - .connect(process.env.CONNECTION_URI, { - useNewUrlParser: true, - useUnifiedTopology: true, - dbName: 'test', - }) - .then(() => { - console.log('MongoDB Connected…'); - }) - .catch(err => console.error(err)); +module.exports = async function (mongoose) { + try { + await mongoose.connect(process.env.CONNECTION_URI); + console.log('✅ MongoDB connected'); + } catch (err) { + console.error('❌ MongoDB connection error:', err); + process.exit(1); + } }; diff --git a/backend/server.js b/backend/server.js index b4a1cd0..5e2e212 100644 --- a/backend/server.js +++ b/backend/server.js @@ -6,36 +6,44 @@ const mongoose = require('mongoose'); require('dotenv').config(); const { sessionMiddleware } = require('./config/session'); -const PORT = process.env.PORT; +const PORT = process.env.PORT || 5000; const app = express(); app.use(cookieParser()); -app.use( - express.urlencoded({ - extended: true, - }) -); +app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.set('trust proxy', 1); + +/* ---------- CORS ---------- */ app.use( cors({ - origin: 'http://localhost:3000', + origin: + process.env.NODE_ENV === 'production' + ? true // same origin (Docker / prod) + : 'http://localhost:3000', credentials: true, }) ); + app.use(sessionMiddleware); -const server = app.listen(PORT); +const server = app.listen(PORT, "0.0.0.0", () => { + console.log(`Server listening on port ${PORT}`); +}); +/* ---------- Mongo + Socket ---------- */ require('./config/database')(mongoose); require('./config/socket')(server); +/* ---------- Serve React build ---------- */ if (process.env.NODE_ENV === 'production') { - app.use(express.static('./build')); + const buildPath = path.resolve(__dirname, 'build'); + + app.use(express.static(buildPath)); + app.get('*', (req, res) => { - const indexPath = path.join(__dirname, './build/index.html'); - res.sendFile(indexPath); + res.sendFile(path.join(buildPath, 'index.html')); }); } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bc2de54 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +version: "3.9" + +services: + mongo: + image: mongo:7.0 + container_name: ludo-mongo + restart: unless-stopped + networks: + - ludo-net + volumes: + - ludo-mongo-data:/data/db + - ./mongo-keyfile:/etc/mongo-keyfile:ro + # - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro + command: + - bash + - -c + - | + cp /etc/mongo-keyfile /data/db/keyfile && + chown mongodb:mongodb /data/db/keyfile && + chmod 400 /data/db/keyfile && + exec mongod --replSet rs0 --keyFile /data/db/keyfile --bind_ip_all + ports: + - "27017:27017" + + app: + build: . + container_name: mern-ludo-app + restart: unless-stopped + networks: + - ludo-net + env_file: + - .env + ports: + - "18081:${PORT}" # Host:Container mapping + depends_on: + - mongo + +networks: + ludo-net: + +volumes: + ludo-mongo-data: \ No newline at end of file diff --git a/src/App.js b/src/App.js index 61034eb..24fa56a 100644 --- a/src/App.js +++ b/src/App.js @@ -13,7 +13,7 @@ function App() { const [playerSocket, setPlayerSocket] = useState(); const [redirect, setRedirect] = useState(); useEffect(() => { - const socket = io(`http://${window.location.hostname}:8080`, { withCredentials: true }); + const socket = io(`${window.location.protocol}//${window.location.host}`, { withCredentials: true }); socket.on('player:data', data => { data = JSON.parse(data); setPlayerData(data); @@ -72,5 +72,3 @@ function App() { ); } - -export default App; diff --git a/troubleshooting.md b/troubleshooting.md new file mode 100644 index 0000000..7d88a1d --- /dev/null +++ b/troubleshooting.md @@ -0,0 +1,562 @@ +You’ve identified the Mongo volume that’s causing the auth issue. + +What this means +local mern-ludo_mongo_data + + +This volume still exists, so Mongo is: + +reusing old, broken initialization + +not recreating the admin user + +continuing to fail authentication + +We now need to delete this volume so Mongo can initialize cleanly. + +✅ Do this EXACTLY (safe + correct) +🔴 Step 1: Stop containers +docker compose down + +🔴 Step 2: Remove the Mongo volume +docker volume rm mern-ludo_mongo_data + + +If Docker complains it’s in use, run: + +docker compose down -v + + +(that removes volumes automatically) + +✅ Step 3: Confirm it’s gone +docker volume ls | grep ludo + + +👉 This should return nothing. + +✅ Step 4: Start ONLY Mongo first (important) +docker compose up -d mongo + + +Wait 10–15 seconds. + +Check logs: + +docker logs ludo-mongo --tail=30 + + +You should NOT see: + +bad file + +Unable to acquire security key + +crash/restart loops + +✅ Step 5: Test authentication (this MUST work) +docker exec -it ludo-mongo mongosh -u admin -p adminpassword --authenticationDatabase admin + + +If you get a > prompt → 🎉 auth is fixed + +✅ Step 6: Initialize replica set (ONCE) + +Inside mongosh: + +rs.initiate({ + _id: "rs0", + members: [{ _id: 0, host: "mongo:27017" }] +}) + + +Then: + +rs.status().members[0].stateStr + + +Must be: + +"PRIMARY" + +✅ Step 7: Start the app +docker compose up -d app + + +(or just) + +docker compose up -d + + +Then: + +docker restart mern-ludo-app + +🎯 Expected final result +Mongo + +Auth works + +Replica set PRIMARY + +No errors in logs + +Backend +MongoDB connected +Server listening on port 18081 + +Browser + +App loads + +No crashes + +No noscript / auth errors + +🧾 One-line status + +The Mongo volume still existed; deleting it allows Mongo to create the admin user correctly. + +Once Step 5 succeeds, you are fully unblocked. +Run Step 2 now and tell me when mongosh login works 👍 + + +You’re very close, and the remaining issue is not random. + +What the two messages really mean (important) +1️⃣ These messages are NOT the main problem ❌ +Collection [local.oplog.rs] not found +ReadConcernMajorityNotAvailableYet + + +These appear when: + +replica set is not initiated yet + +PRIMARY is not elected yet + +They are expected noise before rs.initiate() succeeds. + +👉 We’ll fix them automatically once the replica set is initialized. + +2️⃣ THIS is the real blocker 🔴 +MongoServerError: Authentication failed + + +This means 100%: + +🔐 MongoDB is running with authentication enabled, +❌ but the admin user does not exist. + +This is why: + +backend can’t connect + +mongosh -u admin fails + +oplog can’t be created + +replica set can’t complete + +Why the admin user does NOT exist (root cause) + +Mongo creates the root user only once, on first successful startup, when: + +/data/db is empty + +Mongo reaches a stable running state + +Earlier, Mongo: + +crashed due to keyFile issues + +restarted several times + +skipped user creation + +but auth stayed enabled + +Result: + +Mongo requires auth, but no users exist → permanent auth failure + +This is a classic Mongo + replica set + keyFile edge case. + +✅ The ONLY correct fix (clean & guaranteed) + +We must let Mongo start once without auth, create the user manually, then re-enable auth. + +This is the official MongoDB recovery method. + +🔥 DO THIS STEP-BY-STEP (no skipping) +STEP 1️⃣ Stop everything +docker compose down + +STEP 2️⃣ Temporarily DISABLE auth (Mongo only) + +Edit docker-compose.yml mongo service: + +🔴 TEMPORARY CHANGE + +Comment out these lines for now: + +# environment: +# MONGO_INITDB_ROOT_USERNAME: admin +# MONGO_INITDB_ROOT_PASSWORD: adminpassword + + +And change the command to NO keyFile, NO auth: + +command: + - mongod + - --replSet + - rs0 + - --bind_ip_all + + +(Leave volumes as-is.) + +STEP 3️⃣ Start Mongo only +docker compose up -d mongo + + +Wait ~10 seconds. + +STEP 4️⃣ Connect WITHOUT auth (this must work) +docker exec -it ludo-mongo mongosh + + +If you get a prompt → good. + +STEP 5️⃣ Create admin user MANUALLY + +Inside mongosh: + +use admin +db.createUser({ + user: "admin", + pwd: "adminpassword", + roles: [ { role: "root", db: "admin" } ] +}) + + +You must see: + +{ ok: 1 } + +STEP 6️⃣ Initialize replica set (NOW it will work) +rs.initiate({ + _id: "rs0", + members: [{ _id: 0, host: "mongo:27017" }] +}) + + +Wait ~5–10 seconds, then: + +rs.status().members[0].stateStr + + +Must be: + +"PRIMARY" + + +Exit mongosh: + +exit + +STEP 7️⃣ Re-enable auth + keyFile (FINAL config) + +Restore your correct mongo config: + +environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: adminpassword + +command: + - bash + - -c + - | + cp /tmp/mongo-keyfile /data/db/keyfile && + chown mongodb:mongodb /data/db/keyfile && + chmod 400 /data/db/keyfile && + exec mongod --replSet rs0 --keyFile /data/db/keyfile --bind_ip_all + +STEP 8️⃣ Restart clean +docker compose down +docker compose up -d + +STEP 9️⃣ Test auth (this WILL work now) +docker exec -it ludo-mongo mongosh -u admin -p adminpassword --authenticationDatabase admin + +STEP 🔟 Start / restart backend +docker restart mern-ludo-app + +✅ What you should see now +Mongo + +Auth works + +PRIMARY elected + +local.oplog.rs exists + +No auth errors + +Backend +MongoDB connected +Server listening on port 18081 + +App + +Loads normally + +No crashes + +Change Streams work + +🧠 One-line final diagnosis + +MongoDB authentication was enabled before any user existed; manual user creation was required to recover. + +This is the last MongoDB trap — once done, you will not hit this again. + +MongoServerError[NotWritablePrimary]: not primary + +Perfect — that error is expected at this exact moment, and it tells us precisely what to do next 👍 +You didn’t break anything. + +What this error means (very clear) +MongoServerError[NotWritablePrimary]: not primary + + +This means: + +MongoDB is running as a replica set member, +but no PRIMARY has been elected yet. + +Until a node becomes PRIMARY: + +❌ you cannot create users + +❌ you cannot write data + +❌ db.createUser() will fail + +So this is not an auth issue anymore. + +✅ Correct order (important) + +When running Mongo as a replica set, the order must be: + +Start Mongo + +Initiate replica set + +Wait until PRIMARY + +Create users + +Enable auth (already planned) + +Right now, you’re at step 2½. + +✅ DO THIS NOW (inside mongosh) + +You are already connected with: + +docker exec -it ludo-mongo mongosh + + +At the > prompt, run THIS FIRST 👇 + +🔥 Step 1: Initiate replica set +rs.initiate({ + _id: "rs0", + members: [ + { _id: 0, host: "mongo:27017" } + ] +}) + +Expected output +{ ok: 1 } + +🔥 Step 2: Wait a few seconds, then verify PRIMARY +rs.status().members[0].stateStr + + +You must see: + +"PRIMARY" + + +If it still says STARTUP or SECONDARY, wait 5 seconds and run again. + +✅ ONLY AFTER PRIMARY → create admin user + +Now run: + +use admin + +db.createUser({ + user: "admin", + pwd: "adminpassword", + roles: [ { role: "root", db: "admin" } ] +}) + +Expected: +{ ok: 1 } + +🧠 Why this happened (important lesson) + +You started Mongo with: + +mongod --replSet rs0 + + +That automatically puts Mongo into replica set mode, but: + +replica set is inactive + +no PRIMARY exists yet + +Mongo rejects all writes until a PRIMARY is elected. + +This is correct MongoDB behavior. + +✅ After user creation (next steps preview) + +Once { ok: 1 } appears: + +Exit mongosh: + +exit + + +Re-enable auth + keyFile in docker-compose (as discussed) + +Restart containers + +Verify: + +docker exec -it ludo-mongo mongosh -u admin -p adminpassword --authenticationDatabase admin + +🎯 One-line status update + +MongoDB is in replica-set mode but not PRIMARY yet — initialize the replica set first. + +👉 Action for you now + +Run rs.initiate(...), wait for PRIMARY, then retry db.createUser. + +Tell me what rs.status().members[0].stateStr prints, and we’ll finish this cleanly 💪 + + +```yaml +version: "3.9" + +services: + mongo: + image: mongo:7.0 + container_name: ludo-mongo + restart: unless-stopped + networks: + - ludo-net + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: adminpassword + volumes: + - ludo-mongo-data:/data/db + - ./mongo-keyfile:/tmp/mongo-keyfile:ro + command: + - bash + - -c + - | + cp /tmp/mongo-keyfile /data/db/keyfile && + chown mongodb:mongodb /data/db/keyfile && + chmod 400 /data/db/keyfile && + exec mongod --replSet rs0 --keyFile /data/db/keyfile --bind_ip_all + ports: + - "27017:27017" + + app: + build: . + container_name: mern-ludo-app + restart: unless-stopped + networks: + - ludo-net + env_file: + - .env + ports: + - "18081:8080" + depends_on: + - mongo + +networks: + ludo-net: + +volumes: + ludo-mongo-data: +``` + +Step 2️⃣ Recreate keyfile cleanly (one last time) +cd ~/mern-ludo +rm -f mongo-keyfile +openssl rand -base64 756 > mongo-keyfile +chmod 400 mongo-keyfile + + +Verify: + +wc -c mongo-keyfile + +Step 3️⃣ Full reset (MANDATORY) +docker compose down -v +docker compose up -d --build + + +Wait ~10 seconds. + +Step 4️⃣ Confirm Mongo is RUNNING (not restarting) +docker ps + + +You should NOT see Restarting. + +Step 5️⃣ Now exec WILL work +docker exec -it ludo-mongo mongosh -u admin -p adminpassword --authenticationDatabase admin + + +If you get a shell → 🎉 Mongo is fixed + +Step 6️⃣ Initialize replica set (ONCE) +rs.initiate({ + _id: "rs0", + members: [{ _id: 0, host: "mongo:27017" }] +}) + + +Check: + +rs.status().members[0].stateStr +// PRIMARY + +Step 7️⃣ Restart app +docker restart mern-ludo-app + + +Your Change Stream error will now be gone permanently. + +🧠 Why ALL previous attempts failed +Attempt Why it failed +Bind mount keyfile Ownership mismatch +chmod 400 only Not enough +DietPi ARM Stricter FS behavior +Mongo 7 Enforces keyfile rules hard + +This copy + chown pattern solves all of them. + +✅ One-line final diagnosis + +MongoDB rejected the keyfile because bind-mounted files keep host ownership, and Mongo runs as a non-root user. +