Installation Docker OCI - OpenCCU/OpenCCU GitHub Wiki
It is possible to run OpenCCU as a Docker/OCI container on existing amd64, aarch64/arm64, or arm systems. While the container provides almost all functionality of a “normal” OpenCCU system, certain features—such as network setup or the WebUI‑based update mechanism—are intentionally disabled, since these operations are typically performed on the host system rather than inside the container.
As with a standard OpenCCU installation, you will need compatible Homematic RF modules. However, the relevant kernel drivers for devices like RPI-RF-MOD, HM-MOD-RPI-PCB, HmIP-RFUSB as well as HB‑RF‑USB / HB‑RF‑USB‑2 and HB‑RF‑ETH must be installed on the host, not inside the container. The container will then use these preloaded drivers.
You can install these drivers either via the dedicated install-docker.sh script or manually. In either case, the required kernel modules (kindly provided and maintained by @alexreinert via piVCCU) are installed on the host.
Important
To communicate with a HmIP-HAP or HmIPW-DRAP, the approach below uses a macvlan Docker network. This requires two static IP addresses—<IP-ADDRESS> and <AUX-ADDRESS>—from your LAN that are outside your DHCP range (i.e., not assigned by your router). Assign <IP-ADDRESS> to the container and <AUX-ADDRESS> to the Docker host so host and container can reach each other.
-
Install Docker on the host where the container will run:
sudo sh -c "wget -qO - https://get.docker.com | bash -" -
Add your user to the
dockergroup so it can run Docker commands:sudo usermod -aG docker $USER exec su -l $USER
-
Verify Docker works with the hello‑world example:
docker run hello-world
After completing these steps, your host is ready to run standard Docker containers.
To set up all requirements and run the OpenCCU container you can either use the script‑based approach (install-docker.sh) or follow the manual steps using docker pull, docker load, or a docker compose‑based workflow.
Placeholders used below: replace these with values that match your environment.
-
<IP-ADDRESS>— the static IP (e.g.,192.168.178.4) to assign to the container; choose one from your LAN outside the DHCP range. -
<AUX-ADDRESS>— an auxiliary static IP (e.g.,192.168.178.3) to assign to the host, so host and container can communicate on the same subnet; again outside the DHCP range and not the host’s main IP. -
<INTERFACE>— the host’s primary network interface (e.g.,eth0) connected to your LAN. -
<SUBNET>— the LAN subnet (e.g.,192.168.178.0/24). -
<GATEWAY>— the default gateway IP (e.g.,192.168.178.1).
If you prefer a streamlined setup (or have limited Linux/Docker experience), use the all‑in‑one installer:
-
Run:
wget -qO - https://openccu.de/install-docker.sh | bash -If the script requests elevated privileges, rerun it with
sudo:sudo sh -c "wget -qO - https://openccu.de/install-docker.sh | bash -"During installation, the script may prompt for:
-
<IP-ADDRESS>— container IP (static, non‑DHCP) -
<AUX-ADDRESS>— auxiliary host IP (static, non‑DHCP) -
<INTERFACE>,<SUBNET>,<GATEWAY>— auto‑detected but can be adjusted
-
-
Start the container:
docker start -i ccu
Note: Omit
-ito start detached in the background.
You can rerun the script occasionally to verify your Docker setup or to adapt to changes in OpenCCU. If you downloaded the script, remember to update it periodically to pick up improvements.
If you prefer full control (or are using tools like Docker Compose), follow these steps.
Install third‑party dependencies on the Docker host so the OpenCCU container can access Homematic RF hardware correctly:
-
Install
pivccu-modules-dkms(drivers forRPI-RF-MOD,HM-MOD-RPI-PCB,HmIP-RFUSB):sudo apt install wget ca-certificates build-essential bison flex libssl-dev gpg wget -qO - https://apt.pivccu.de/piVCCU/public.key | sudo gpg --dearmor -o /usr/share/keyrings/pivccu-archive-keyring.gpg sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/pivccu-archive-keyring.gpg] https://apt.pivccu.de/piVCCU stable main" >/etc/apt/sources.list.d/pivccu.list' sudo apt update sudo apt install pivccu-modules-dkms
-
Raspberry Pi with GPIO‑attached RF module (
RPI-RF-MOD/HM-MOD-RPI-PCB) — not required forHB-RF-USB,HB-RF-USB-2,HB-RF-ETH, orHmIP-RFUSB:-
Install device‑tree patches:
sudo apt install pivccu-modules-raspberrypi
-
Disable Bluetooth:
sudo bash -c 'cat <<EOT >>/boot/config.txt dtoverlay=disable-bt EOT' systemctl is-active --quiet hciuart.service && sudo systemctl disable hciuart.service
Note: If
/boot/config.txtdoes not exist, use/boot/firmware/usercfg.txt. -
Disable serial console:
sudo sed -i /boot/cmdline.txt -e "s/console=\(serial0\|ttyAMA0\),[0-9]\+ //"Alternate method (if you run into problems):
sudo bash -c 'cat <<EOT >>/boot/config.txt dtoverlay=miniuart-bt core_freq=250 EOT'
Note: If
/boot/config.txtdoes not exist, use/boot/firmware/usercfg.txt.Disable and mask any serial getty on
ttyAMA0:sudo systemctl stop [email protected] && sudo systemctl disable [email protected] && sudo systemctl mask [email protected]
-
-
HmIP-RFUSB — ensure no conflicting udev rule is present:
sudo rm -f /etc/udev/rules.d/10-hmiprfusb.rules
-
Create udev rules for Homematic devices:
sudo bash -c 'cat <<EOF >/etc/udev/rules.d/99-Homematic.rules ATTRS{idVendor}=="1b1f" ATTRS{idProduct}=="c020", ENV{ID_MM_DEVICE_IGNORE}="1" ATTRS{idVendor}=="1b1f" ATTRS{idProduct}=="c00f", ENV{ID_MM_DEVICE_IGNORE}="1" ATTRS{idVendor}=="0403" ATTRS{idProduct}=="6f70", ENV{ID_MM_DEVICE_IGNORE}="1" ATTRS{idVendor}=="10c4" ATTRS{idProduct}=="8c07", ENV{ID_MM_DEVICE_IGNORE}="1" EOF'
-
Load
eq3_char_loopat boot:sudo sh -c 'echo eq3_char_loop >/etc/modules-load.d/eq3_char_loop.conf' -
Start/load required kernel modules now:
sudo service pivccu-dkms start sudo modprobe eq3_char_loop
Note: If
modprobe eq3_char_loopfails, update kernel headers (common on Raspberry Pi OS 64‑bit):sudo apt update sudo apt install raspberrypi-kernel raspberrypi-kernel-headers raspberrypi-bootloader
Then repeat:
sudo apt install --reinstall pivccu-modules-dkms sudo sh -c 'echo eq3_char_loop >/etc/modules-load.d/eq3_char_loop.conf' -
Create a
macvlannetwork namedccu(skip if you use docker compose below to create it automatically):docker network create -d macvlan \ --opt parent=<INTERFACE> \ --subnet <SUBNET> \ --gateway <GATEWAY> \ ccuNote: Replace all
<…>placeholders as described above. -
Set up a “shim” link so the host can reach the container (macvlan isolates host from containers by default):
sudo ip link add ccu-shim link <INTERFACE> type macvlan mode bridge sudo ip addr add <AUX-ADDRESS> dev ccu-shim sudo ip link set ccu-shim up sudo ip route add <IP-ADDRESS> dev ccu-shim protocol static
These
ipcommands are not persistent; run them on every boot or add them to a boot‑time script.Example for Debian/Ubuntu: create
/etc/network/if-up.d/99-ccu-shim-network:#!/bin/sh if [ "$IFACE" = "<INTERFACE>" ]; then if ! ip link show ccu-shim >/dev/null 2>&1; then ip link add ccu-shim link <INTERFACE> type macvlan mode bridge ip addr add <AUX-ADDRESS> dev ccu-shim ip link set ccu-shim up ip route add <IP-ADDRESS> dev ccu-shim protocol static fi fi
Then:
sudo chmod a+rx /etc/network/if-up.d/99-ccu-shim-network
You can create/run the container via docker pull, docker load, or Docker Compose (or use the install-docker.sh script). Replace all <…> placeholders accordingly.
- Pull the latest image:
docker pull ghcr.io/openccu/openccu:latest
- Create the container:
docker create --name ccu \ --read-only \ --volume ccu_data:/usr/local:rw \ --volume /lib/modules:/lib/modules:ro \ --volume /run/udev/control:/run/udev/control \ --privileged --restart always --stop-timeout 30 \ --network ccu --ip <IP-ADDRESS> --hostname ccu \ ghcr.io/openccu/openccu:latest - Start it:
Note: Omit
docker start -i ccu
-ito run detached.
- Download the latest OpenCCU Docker/OCI image:
wget https://github.com/OpenCCU/OpenCCU/releases/download/3.XX.XX.YYYYMMDD/OpenCCU-3.XX.XX.YYYYMMDD-oci_amd64.tgz
- Load it into Docker:
docker load < OpenCCU-3.XX.XX.YYYYMMDD-oci_amd64.tgz - Create the container:
docker create --name ccu \ --read-only \ --volume ccu_data:/usr/local:rw \ --volume /lib/modules:/lib/modules:ro \ --volume /run/udev/control:/run/udev/control \ --privileged --restart always --stop-timeout 30 \ --network ccu --ip <IP-ADDRESS> --hostname ccu \ ghcr.io/openccu/openccu:amd64-3.XX.XX.YYYYMMDD - Start it:
Note: Omit
docker start -i ccu
-ito run detached.
- Add to your
docker-compose.yml:version: "3.8" services: openccu: image: ghcr.io/openccu/openccu:latest container_name: ccu hostname: ccu read_only: true privileged: true restart: unless-stopped stop_grace_period: 30s volumes: - ccu_data:/usr/local:rw - /lib/modules:/lib/modules:ro - /run/udev/control:/run/udev/control networks: ccu: ipv4_address: <IP-ADDRESS> volumes: ccu_data: networks: ccu: name: ccu driver: macvlan driver_opts: parent: <INTERFACE> ipam: config: - subnet: <SUBNET> gateway: <GATEWAY>
- Start via Compose:
docker compose up -d
-
ERROR: could not insert 'eq3_char_loop': Exec format error
The required kernel modules could not be compiled for your host. Try:sudo apt remove --purge linux-headers-* sudo rm -rf /usr/src/linux-headers-* sudo apt autoremove && sudo apt autoclean sudo apt install linux-headers-generic sudo apt install --reinstall pivccu-modules-dkms
-
Slow or unreliable radio communication
Ensure the container has sufficient CPU shares to process radio messages in time. Add--cap=sys_niceand tweak CPU settings indocker run, or in Compose:openccu: # ... cap_add: - SYS_NICE cpu_shares: 4096 # 4x more CPU cycles during peaks deploy: update_config: order: stop-first resources: reservations: cpus: '0.6' memory: 256M
-
(Partly obsolete)
cpu.rt_runtime_us == 0errors indocker logs ccu
Your host kernel hasCONFIG_RT_GROUP_SCHEDenabled and the Docker daemon lacks sufficient real‑time runtime.-
Set Docker daemon option in
/etc/docker/daemon.json:{ "cpu-rt-runtime": 950000 }Then restart Docker:
sudo systemctl restart docker. -
Add appropriate options depending on your method:
-
install-docker.sh: no action needed in recent versions. -
docker pull/docker load(run command): add--cpu-rt-runtime 950000 --ulimit rtprio=99
-
Docker Compose (
docker-compose.yml):cpu_rt_runtime: 950000 ulimits: rtprio: 99
-
-
Point your browser to the container IP:
http://<IP-ADDRESS>/
Either enable SSH in the CCU WebUI, or:
docker exec -it ccu /bin/shUpdate from the host (the Docker‑native way) using the same approach you used initially—e.g., rerun install-docker.sh, docker pull, or update via Compose—to fetch and start the latest image.
To remove the entire OpenCCU container setup (and clean up networks/configs), run the installer with the uninstall parameter:
wget -qO - https://openccu.de/install-docker.sh | sudo bash -s uninstallThis removes containers, networks, and related config files. After a reboot, only the data volume should remain.
You can pass environment variables to override defaults at runtime:
-
CCU_DATA_VOLUME
Name of the Docker volume for persistent CCU data (can also point to a mounted NAS, cluster FS, etc.).
Default:ccu_data -
CCU_OCI_REPO
Container image repository to use.
Default:ghcr.io/openccu/openccu -
CCU_OCI_TAG
Container image tag.
Default:latest -
CCU_CONTAINER_NAME
Container instance name (also used as--hostname).
Default:ccu -
CCU_CONTAINER_IP
Static container IP (e.g.,192.168.178.4), must be outside the DHCP range.
Default: (empty; prompted interactively) -
CCU_CONTAINER_IP_AUX
Auxiliary host IP (e.g.,192.168.178.3), same subnet as above, non‑DHCP.
Default: (empty; prompted interactively) -
CCU_NETWORK_NAME
Name of the Docker macvlan network.
Default:ccu -
CCU_NETWORK_INTERFACE
Host interface (e.g.,eth0,ensXX).
Default: (auto‑detected or prompted) -
CCU_NETWORK_SUBNET
Subnet (e.g.,192.168.178.0/24).
Default: (auto‑detected or prompted) -
CCU_NETWORK_GATEWAY
Gateway IP (e.g.,192.168.178.1).
Default: (auto‑detected or prompted) -
CCU_DOCKER_RUN_OPTIONS
Additional options fordocker run.
Default: (empty) -
CCU_DOCKER_PULL_OPTIONS
Additional options fordocker pull.
Default: (empty) -
CCU_DOCKER_PULL_REFRESH
Whether to rundocker pullto refresh the image.
Default:true -
CCU_DOCKER_STOP_TIMEOUT
Time (seconds) allowed to stop the container before Docker kills it.
Default:30