Operations Guide
Day-to-day operational guidance for running MatrixEasyMode in an operator-managed environment.
Use this page for normal day-to-day operations: checking status, reading logs, restarting services, and understanding the expected operating model.
For first deployment, start with Get Started and then the Installation Guide.
This guide explains the normal operating model for MatrixEasyMode once it has been installed.
MatrixEasyMode is currently packaged and documented for serious self-hosters and infrastructure-capable operators. That means the runtime model is explicit, staged, and intended to be reasoned about clearly.
This page focuses on:
- normal day-to-day operator workflow
- stack lifecycle commands
- reading status and logs
- restart discipline
- expectations around infrastructure versus application services
- safe habits for running MatrixEasyMode in production-like environments
Runtime model
MatrixEasyMode runs with a staged deployment model:
- infrastructure first
- PostgreSQL
- Nginx Proxy Manager
- application second
- MatrixEasyMode API
- MatrixEasyMode web frontend
This separation is intentional.
The infrastructure layer provides the baseline services the app layer depends on. In particular, the MatrixEasyMode API expects Nginx Proxy Manager and certificate prerequisites to already be in place before the app layer is started.
Operator mindset
For the current phase of MatrixEasyMode, the expected operator workflow is:
- treat
.envas the source of runtime intent - start infrastructure before application services
- verify logs and state before making changes
- restart deliberately rather than repeatedly guessing
- keep ingress, certificates, and DNS in sync with the deployment model
This is not a one-click hidden-behavior product. The operating model is meant to be explicit.
Core lifecycle commands
Check current state
./stack.sh statusUse this first whenever you want to understand what is currently running.
Start infrastructure only
./stack.sh up infraThis starts:
postgresnpm
Start application only
./stack.sh up appThis starts:
apiweb
Start everything
./stack.sh up allUse this when you intentionally want the full stack running.
Stop application only
./stack.sh down appStop infrastructure only
./stack.sh down infraStop everything
./stack.sh down allRestart the application layer
./stack.sh restart appThis is usually the safest targeted restart operation for day-to-day app changes or environment corrections.
Reading logs
Logs are one of the primary tools for understanding MatrixEasyMode's runtime state.
Follow infrastructure logs
./stack.sh logs infraUse this when checking PostgreSQL or Nginx Proxy Manager state.
Follow application logs
./stack.sh logs appUse this when checking the API and web frontend together.
Follow a specific service
./stack.sh logs api
./stack.sh logs web
./stack.sh logs postgres
./stack.sh logs npmUse targeted logs when you already know which layer you are investigating.
When to use each log stream
logs infra
Use this when the issue is likely related to:
- database startup
- Nginx Proxy Manager availability
- certificate readiness
- ingress prerequisites
- infrastructure health before app startup
logs app
Use this when the issue is likely related to:
- API startup
- frontend startup
- auth/config issues
- app-layer route/bootstrap behavior
- browser-facing runtime problems
logs api
Use this when the problem is likely related to:
- NPM integration
- API startup failures
- auth token issues
- configuration binding issues
- route bootstrap logic
logs web
Use this when the problem is likely related to:
- frontend startup
- NextAuth behavior
- public URL mismatches
- web-to-API configuration
Safe startup order
A good normal operator sequence is:
- review or trust the current
.env - start infrastructure
- verify NPM is reachable and certificate prerequisites are satisfied
- start the application layer
- verify status
- inspect logs if anything looks unusual
Typical command flow:
./stack.sh up infra
./stack.sh status
./stack.sh up app
./stack.sh status
./stack.sh logs appSafe restart discipline
Avoid repeatedly bouncing the whole stack without understanding what changed.
Prefer this approach:
If the app configuration changed
Restart only the app layer:
./stack.sh restart appIf infrastructure was not running
Bring up infrastructure first:
./stack.sh up infraThen start the app layer:
./stack.sh up appIf you changed local-mode images
Rebuild first:
./stack.sh build appThen start or restart the app layer.
Application updates
For application-layer updates, use:
./stack.sh update appThis is the intended update path for the app layer.
Infrastructure upgrades such as PostgreSQL or Nginx Proxy Manager should be handled deliberately and manually, with proper caution, because they affect foundational services and persistent state.
Operating in registry mode
Registry mode is the normal path for published images.
Typical values include:
MEM_IMAGE_SOURCE=registry
MEM_REGISTRY=...
MEM_VERSION=...Operationally, registry mode usually means:
- you do not build images locally
- updates are driven by image tag changes
- the standard helper-script lifecycle is the cleanest path
Operating in local mode
Local mode is intended for contributors or internal development.
Typical values include:
MEM_IMAGE_SOURCE=local
MEM_API_IMAGE=...
MEM_WEB_IMAGE=...Operationally, local mode usually means:
- local images must be built before app start
docker-compose.local.ymlmust be included- local repository layout must match expected build contexts
- local image tags in
.envmust match what was built
A common local-mode lifecycle is:
./stack.sh build app
./stack.sh up infra
./stack.sh up appDay-to-day operational checks
A healthy day-to-day operator checklist looks like this:
.envreflects the intended deployment- infrastructure is running
- NPM is reachable
- wildcard certificate exists in NPM
- app layer is running
- public URLs and DNS still match deployment expectations
- logs do not show repeated bootstrap or integration failures
Ingress expectations
MatrixEasyMode uses Nginx Proxy Manager for the main web and API entrypoints.
That means operators should periodically confirm:
- NPM credentials in
.envare still correct INGRESS_CERTIFICATE_NAMEstill matches the real certificate in NPM- public routes still point to the correct backends
- public DNS still resolves correctly
Do not treat ingress as a “set and forget” black box. It is part of the runtime model.
Environment discipline
The current deployment pack is environment-driven. That means:
.envchanges matter- image-mode selection matters
- public URL values matter
- NPM integration values matter
- internal versus public addresses matter
Before troubleshooting runtime behavior, review the actual environment file:
cat .envTreat .env as sensitive and protect it appropriately:
chmod 600 .envWhen something looks wrong
Use this sequence:
-
check status
bashbash./stack.sh status -
inspect infrastructure logs
bashbash./stack.sh logs infra -
inspect app logs
bashbash./stack.sh logs app -
review
.envbashbashcat .env -
confirm NPM and certificate state
-
confirm public URLs and DNS
-
if using local mode, confirm images were built and tags are correct
This sequence usually narrows the problem down quickly.
Normal versus abnormal behavior
Normal
Examples of normal operator behavior include:
- starting infrastructure first
- starting the app layer second
- following logs after changes
- targeted restarts of the app layer
- explicit environment review when something changes
Abnormal
Examples of risky or unhelpful behavior include:
- starting the app layer before NPM is ready
- repeatedly restarting the whole stack without reading logs
- leaving public URLs on localhost in a real deployment
- forgetting to build images in local mode
- assuming ingress or certificate state is correct without checking
Raw Docker Compose usage
Advanced operators may sometimes prefer raw Compose commands.
Registry mode:
docker compose up -d
docker compose --profile app up -d api web
docker compose --profile app ps
docker compose --profile app logs -f api webLocal mode:
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d postgres npm
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app up -d api web
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app ps
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app logs -f api webThe script-first model is still preferred, but raw Compose is a valid operator path when used deliberately.
Related documentation
Final note
MatrixEasyMode operations are intentionally explicit.
That means the correct operator approach is not to hide the runtime model, but to understand it:
- infrastructure first
- application second
- review environment
- inspect logs
- restart deliberately
- keep ingress and public identity aligned with configuration
That explicitness is part of the product posture in this phase.
