Here’s a full end-to-end “how do I self-host this thing with docker-compose” walkthrough.
I’ll assume:
-
You’re running on a Linux server (Ubuntu/Debian style) with shell access.
-
Your stack is:
core(Express/TypeScript API)([GitHub][1])console(Next.js frontend)([GitHub][2])mongo(database)
-
Your
docker-compose.ymllives athttps://github.com/Senzops/.github/blob/dev/docker-compose.ymland wires those three together.
On a fresh Ubuntu/Debian server (run as a sudo user):
# Update packages
sudo apt-get update
# Install Docker
sudo apt-get install -y ca-certificates curl gnupg
# Official Docker repo (simplified from Docker docs)
curl -fsSL https://get.docker.com | sudo sh
# Enable & start Docker
sudo systemctl enable docker
sudo systemctl start dockerDocker Compose v2 is now built into docker as docker compose.([Docker Documentation][3])
Check:
docker --version
docker compose versionPick a root folder where the whole stack will live:
mkdir -p ~/senzor-stack
cd ~/senzor-stackYour final structure will look like:
senzor-stack/
core/
console/
docker-compose.yml
.env # optional, for secrets
From inside ~/senzor-stack:
git clone https://github.com/Senzops/core.git
git clone https://github.com/Senzops/console.gitYou should now have core/ and console/ in this directory.
Still from ~/senzor-stack, you have two options:
-
Open
https://github.com/Senzops/.github/blob/dev/docker-compose.ymlin your browser. -
Click Raw.
-
Copy all contents.
-
On your server:
nano docker-compose.yml
Paste the contents and save.
From your server, something like:
curl -L "https://raw.githubusercontent.com/Senzops/.github/dev/docker-compose.yml" -o docker-compose.ymlIf that exact raw URL ever differs, just grab whatever GitHub shows on the Raw view.
If your docker-compose.yml uses placeholders or references environment variables for Firebase / Mongo passwords, add them to a .env file next to docker-compose.yml:
cd ~/senzor-stack
nano .envExample content (adjust to match your compose file):
# --- Mongo credentials (example) ---
MONGO_ROOT_USER=senzore_root
MONGO_ROOT_PASSWORD=some-long-random-password
# --- Core service ---
FIREBASE_SERVICE_ACCOUNT='{"type":"service_account","project_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n..."}'
## Demo User (firebaseUid)
## OPTIONAL: Add when demo access required
DEMO_USER_ID=senzor-demo-account
# --- Console (Next.js) ---
NEXT_PUBLIC_API_URL=http://localhost:5000/api
NEXT_PUBLIC_FIREBASE_API_KEY=your-firebase-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-idThen, in docker-compose.yml, it will either:
- Directly read from
.envautomatically (compose does this by default), or - Use
${VAR_NAME}in theenvironment:blocks, like:
services:
core:
environment:
MONGO_URI: "mongodb://$MONGO_ROOT_USER:$MONGO_ROOT_PASSWORD@mongo:27017/senzore?authSource=admin"
FIREBASE_SERVICE_ACCOUNT: "${FIREBASE_SERVICE_ACCOUNT}"
DEMO_USER_ID: "${DEMO_USER_ID}"
console:
environment:
NEXT_PUBLIC_API_URL: "${NEXT_PUBLIC_API_URL}"
NEXT_PUBLIC_FIREBASE_API_KEY: "${NEXT_PUBLIC_FIREBASE_API_KEY}"
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: "${NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN}"
NEXT_PUBLIC_FIREBASE_PROJECT_ID: "${NEXT_PUBLIC_FIREBASE_PROJECT_ID}"Important: Make sure .env is never committed to Git.
You should already have Dockerfiles in:
core/Dockerfile– builds the Express API (TypeScript → dist →npm start)console/Dockerfile– builds Next.js production app (npm run build→npm start)
From ~/senzor-stack:
ls core
ls consoleYou should see Dockerfile in both.
If your compose file references them like:
core:
build:
context: ./core
console:
build:
context: ./console…you’re good.
By default, likely:
- Mongo: internal name
mongoand maybe exposed as27017on the host - Core: exposed on host as
5000 - Console: exposed on host as
3000
In docker-compose.yml, check for:
core:
ports:
- "5000:5000"
console:
ports:
- "3000:3000"If you’re putting this behind a reverse proxy (Traefik, Nginx, Caddy), you might:
- Stop exposing ports publicly.
- Instead, expose only via the proxy network.
For first self-hosting, keeping these as-is is fine. You’ll then reach:
- Backend:
http://<server-ip>:5000 - Frontend:
http://<server-ip>:3000
From ~/senzor-stack:
docker compose buildThis will:
- Build the
coreimage using its Dockerfile. - Build the
consoleimage using its Dockerfile. - Pull the
mongoimage from Docker Hub.
Fix any build issues (missing env, wrong paths) before continuing.
Once build succeeds:
docker compose up -dThis will:
- Start MongoDB first.
- Start
core(pointing at the Mongo URI from env / compose). - Start
console(pointing atcoreviaNEXT_PUBLIC_API_URL=http://localhost:5000/api).
Check status:
docker compose psYou should see all three services marked as Up.
If something doesn’t behave:
# See everything
docker compose logs -f
# See only core logs
docker compose logs -f core
# Only console
docker compose logs -f console
# Only mongo
docker compose logs -f mongoCommon things to confirm:
- Mongo: no auth errors (wrong username/password /
authSource). - Core: successfully connects to Mongo (no connection/refused).
- Console: successfully reaches
http://core:5000internally andNEXT_PUBLIC_API_URLis set correctly for browser calls (should behttp://<public-host>:5000/apiin production).
From your laptop / local machine:
-
Get the server’s IP or domain (e.g.
203.0.113.10ormonitoring.example.com). -
Open:
http://<server-ip>:3000 -
The Senzor Console UI should appear.
-
When you log in via Firebase and hit dashboard pages, they will call backend at:
NEXT_PUBLIC_API_URL (e.g. http://<server-ip>:5000/api)
Make sure you configured Firebase Auth correctly in your env variables (matching what’s in the console README).([GitHub][2])
Once it works:
-
Use strong Mongo credentials (long random password in
.env). -
Don’t expose Mongo externally unless absolutely required:
- Either remove
ports: "27017:27017"from Mongo in compose, or firewall it.
- Either remove
-
Use HTTPS:
- Put Nginx / Traefik / Caddy in front of
consoleandcore. - Terminate TLS there and proxy to containers over the internal Docker network.
- Put Nginx / Traefik / Caddy in front of
-
Lock down the server:
- Use UFW / security groups.
- Only allow 80/443 (and maybe 22 for SSH).
When you push new commits to core or console:
cd ~/senzor-stack
# Pull latest code
cd core && git pull && cd ..
cd console && git pull && cd ..
# Rebuild + restart
docker compose build
docker compose up -dDocker will recreate containers with the new images while keeping volumes (e.g. MongoDB data).