I have been an avid user of the MagicMirror² framework for almost 6 years now. I have developed, and look after a range of modules. This document will detail these modules and their usage.
🧱 Features
- Based on
debian:trixiefor Pi 5 compatibility - Installs MagicMirror² v2.32+
- Allows custom modules + volume persistence
- Exposed port for local display
🧪 Custom Modules
- MMM-Growatt for solar stats
- MMM-Growatt-Stats for combined stats
- MMM-MovieListings for movies
- MMM-NOAA3 for weather-forecast from different providers
- MMM-Reddit to display content from Reddit
- MMM-GasMonitor to track your gas levels
- MMM-NewsAPI custom news feed
- MMM-Rugby track world rugby rankings and tracks match results for specified leagues
- MMM-SweepClock a clssic Railway Clock
- MMM-EskomSePush tracks loadshedding schedule in South Africa
- MMM-WOTD a word of the day module which caters for multiple languages
- MMM-PhilipsHue displayes information and status of your Hue lights from your Hue Bridge
🪞 MagicMirror² in Docker — My Complete Setup
- I recently set up MagicMirror² to run fully containerized in Docker with support for:
- Mounted custom modules, config.js, and custom.css
- Server-only mode for remote/browser display
- Clean build → test → push to Docker Hub workflow
Here’s how I did it.
1️⃣ Prepare the Project Structure
Create a working folder for your MagicMirror container:
mkdir magicmirror-docker
cd magicmirror-docker
mkdir config custom-css my-modules
touch config/config.js
touch custom-css/custom.css
- config/ → contains config.js
- custom-css/ → contains custom.css
- my-modules/ → where all your custom modules go
2️⃣ Create the Dockerfile
FROM debian:trixie-20250520
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
ENV DEBIAN_FRONTEND=noninteractive
# Create non-root user
RUN useradd -ms /bin/bash pi
USER root
# Install system deps
RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-recommends \
curl git nano procps tini ca-certificates xz-utils python3 gnupg build-essential \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Dummy sudo for some npm postinstall scripts
RUN echo -e '#!/bin/bash\nexec "$@"' > /usr/local/bin/sudo && chmod +x /usr/local/bin/sudo
# Install Node.js 22.x
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
apt-get install -y nodejs && node -v && npm -v
# Switch to non-root
USER pi
WORKDIR /home/pi
# Clone MagicMirror and install dependencies
RUN git clone https://github.com/MagicMirrorOrg/MagicMirror.git
WORKDIR /home/pi/MagicMirror
RUN npm install && npm run install-mm
# Copy entrypoint script
COPY entrypoint.sh /home/pi/entrypoint.sh
RUN chmod +x /home/pi/entrypoint.sh
EXPOSE 8080
ENTRYPOINT ["/home/pi/entrypoint.sh"]
3️⃣ Create the Entrypoint Script
entrypoint.sh handles linking modules and loading config/css:
#!/bin/bash
set -euxo pipefail
MM_DIR="/home/pi/MagicMirror"
MODULES_DIR="$MM_DIR/modules"
CUSTOM_MODULES_DIR="$MM_DIR/custom-modules"
CUSTOM_CONFIG="/home/pi/MM-config/config.js"
CUSTOM_CSS="/home/pi/MM-css/custom.css"
# Load config.js if provided
if [ -f "$CUSTOM_CONFIG" ]; then
cp "$CUSTOM_CONFIG" "$MM_DIR/config/config.js"
echo "✅ Loaded custom config.js"
fi
# Load custom.css if provided
if [ -f "$CUSTOM_CSS" ]; then
cp "$CUSTOM_CSS" "$MM_DIR/css/custom.css"
echo "✅ Loaded custom.css"
fi
# Link custom modules
if [ -d "$CUSTOM_MODULES_DIR" ]; then
for dir in "$CUSTOM_MODULES_DIR"/*; do
[ -d "$dir" ] || continue
name=$(basename "$dir")
target="$MODULES_DIR/$name"
if [ ! -L "$target" ]; then
ln -s "$dir" "$target"
echo "✅ Linked custom module: $name"
fi
done
fi
# Start MagicMirror in server-only mode
cd "$MM_DIR"
exec npm run server
4️⃣ Docker Compose Setup
docker-compose.yml mounts your local folders into the container:
version: "3.8"
services:
magicmirror:
image: yourusername/magicmirror:latest
container_name: magicmirror
ports:
- "8080:8080"
volumes:
- ./config:/home/pi/MM-config
- ./custom-css:/home/pi/MM-css
- ./my-modules:/home/pi/MagicMirror/custom-modules
restart: unless-stopped
5️⃣ Build, Test, and Run Locally
docker-compose build --no-cache
docker-compose up -d
docker logs -f magicmirror
Visit:
http://localhost:8080
Notes:
- If you are doing these in a Windows environment, you need to have docker-desktop installed.
- You may also want to do the above steps in a WSL environment
6️⃣ Scripts for Automation
build-local.sh (Test Locally)
#!/bin/bash
set -e
docker-compose build --no-cache
docker-compose up -d
build-and-push.sh (Push to Docker Hub)
#!/bin/bash
set -e
DOCKER_USERNAME="yourusername"
IMAGE_NAME="magicmirror"
docker build -t $DOCKER_USERNAME/$IMAGE_NAME:latest .
docker push $DOCKER_USERNAME/$IMAGE_NAME:latest
Make them executable:
chmod +x build-local.sh build-and-push.sh
7️⃣ Browser Display and Portrait Mode
- MagicMirror is running in server-only mode.
- Rotate the display on the viewing device (tablet, monitor, or laptop).
- On Raspberry Pi with a local screen, use /boot/config.txt to set display_rotate=1
✅ Final Notes
- All custom modules, config, and CSS live outside the container for easy updates.
- Core MagicMirror and default modules are baked into the image.
- Upgrading is as simple as:
docker-compose down
docker pull yourusername/magicmirror:latest
docker-compose up -d
This setup gives you a clean, maintainable MagicMirror Docker workflow, from local testing to pushing your own Docker Hub image.
Some screenshots of the modules under my guard
Growatt

Growatt-Stats

EskomSePush

Gas Monitor

MovieListing

NewsAPI

NOAA3

PhilipsHue

Reddit

Rugby

SweepClock

WOTD
