ludo web based game config file changes
This commit is contained in:
parent
4cd0fe970f
commit
5b02a13cb4
8
.env
Normal file
8
.env
Normal file
@ -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
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -21,4 +21,4 @@ build
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
.env
|
# .env
|
||||||
116
Dockerfile
116
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
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy all files
|
||||||
COPY . /app
|
COPY . /app
|
||||||
RUN npm install --production
|
|
||||||
|
# Install frontend (root) dependencies
|
||||||
|
RUN npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
# Build frontend
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM node:14 as backend
|
# Install backend dependencies
|
||||||
WORKDIR /app
|
RUN cd backend && npm install --production --legacy-peer-deps
|
||||||
COPY /backend /app
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
FROM node:14
|
# Move frontend build into backend/public for Express
|
||||||
WORKDIR /app
|
# RUN cp -r build backend/public
|
||||||
COPY --from=backend /app /app/
|
RUN rm -rf backend/build
|
||||||
COPY --from=frontend /app/build /app/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"]
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
module.exports = function (mongoose) {
|
module.exports = async function (mongoose) {
|
||||||
mongoose.set('useFindAndModify', false);
|
try {
|
||||||
mongoose
|
await mongoose.connect(process.env.CONNECTION_URI);
|
||||||
.connect(process.env.CONNECTION_URI, {
|
console.log('✅ MongoDB connected');
|
||||||
useNewUrlParser: true,
|
} catch (err) {
|
||||||
useUnifiedTopology: true,
|
console.error('❌ MongoDB connection error:', err);
|
||||||
dbName: 'test',
|
process.exit(1);
|
||||||
})
|
}
|
||||||
.then(() => {
|
|
||||||
console.log('MongoDB Connected…');
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,36 +6,44 @@ const mongoose = require('mongoose');
|
|||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
const { sessionMiddleware } = require('./config/session');
|
const { sessionMiddleware } = require('./config/session');
|
||||||
|
|
||||||
const PORT = process.env.PORT;
|
const PORT = process.env.PORT || 5000;
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(
|
app.use(express.urlencoded({ extended: true }));
|
||||||
express.urlencoded({
|
|
||||||
extended: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.set('trust proxy', 1);
|
app.set('trust proxy', 1);
|
||||||
|
|
||||||
|
/* ---------- CORS ---------- */
|
||||||
app.use(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
origin: 'http://localhost:3000',
|
origin:
|
||||||
|
process.env.NODE_ENV === 'production'
|
||||||
|
? true // same origin (Docker / prod)
|
||||||
|
: 'http://localhost:3000',
|
||||||
credentials: true,
|
credentials: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use(sessionMiddleware);
|
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/database')(mongoose);
|
||||||
require('./config/socket')(server);
|
require('./config/socket')(server);
|
||||||
|
|
||||||
|
/* ---------- Serve React build ---------- */
|
||||||
if (process.env.NODE_ENV === 'production') {
|
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) => {
|
app.get('*', (req, res) => {
|
||||||
const indexPath = path.join(__dirname, './build/index.html');
|
res.sendFile(path.join(buildPath, 'index.html'));
|
||||||
res.sendFile(indexPath);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
docker-compose.yml
Normal file
42
docker-compose.yml
Normal file
@ -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:
|
||||||
@ -13,7 +13,7 @@ function App() {
|
|||||||
const [playerSocket, setPlayerSocket] = useState();
|
const [playerSocket, setPlayerSocket] = useState();
|
||||||
const [redirect, setRedirect] = useState();
|
const [redirect, setRedirect] = useState();
|
||||||
useEffect(() => {
|
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 => {
|
socket.on('player:data', data => {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
setPlayerData(data);
|
setPlayerData(data);
|
||||||
@ -72,5 +72,3 @@ function App() {
|
|||||||
</SocketContext.Provider>
|
</SocketContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
|
||||||
|
|||||||
562
troubleshooting.md
Normal file
562
troubleshooting.md
Normal file
@ -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.
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user