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

Known limitations

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.


Prerequisites

  1. Install Docker on the host where the container will run:
    sudo sh -c "wget -qO - https://get.docker.com | bash -"
  2. Add your user to the docker group so it can run Docker commands:
    sudo usermod -aG docker $USER
    exec su -l $USER
  3. 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.


Installation Procedure

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).

Automatic Installation

If you prefer a streamlined setup (or have limited Linux/Docker experience), use the all‑in‑one installer:

  1. 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
  2. Start the container:

    docker start -i ccu

    Note: Omit -i to 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.

Manual Installation

If you prefer full control (or are using tools like Docker Compose), follow these steps.

Host Dependencies

Install third‑party dependencies on the Docker host so the OpenCCU container can access Homematic RF hardware correctly:

  1. Install pivccu-modules-dkms (drivers for RPI-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
  2. Raspberry Pi with GPIO‑attached RF module (RPI-RF-MOD / HM-MOD-RPI-PCB) — not required for HB-RF-USB, HB-RF-USB-2, HB-RF-ETH, or HmIP-RFUSB:

    1. Install device‑tree patches:

      sudo apt install pivccu-modules-raspberrypi
    2. 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.txt does not exist, use /boot/firmware/usercfg.txt.

    3. 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.txt does 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] 
  3. HmIP-RFUSB — ensure no conflicting udev rule is present:

    sudo rm -f /etc/udev/rules.d/10-hmiprfusb.rules
  4. 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'
  5. Load eq3_char_loop at boot:

    sudo sh -c 'echo eq3_char_loop >/etc/modules-load.d/eq3_char_loop.conf'
  6. Start/load required kernel modules now:

    sudo service pivccu-dkms start
    sudo modprobe eq3_char_loop

    Note: If modprobe eq3_char_loop fails, 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'
  7. Create a macvlan network named ccu (skip if you use docker compose below to create it automatically):

    docker network create -d macvlan \
                          --opt parent=<INTERFACE> \
                          --subnet <SUBNET> \
                          --gateway <GATEWAY> \
                          ccu

    Note: Replace all <…> placeholders as described above.

  8. 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 ip commands 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

Container Setup / Startup

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.

Using docker pull
  1. Pull the latest image:
    docker pull ghcr.io/openccu/openccu:latest
  2. 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
  3. Start it:
    docker start -i ccu
    Note: Omit -i to run detached.
Using docker load
  1. 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
  2. Load it into Docker:
    docker load < OpenCCU-3.XX.XX.YYYYMMDD-oci_amd64.tgz
  3. 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
  4. Start it:
    docker start -i ccu
    Note: Omit -i to run detached.
Using docker compose
  1. 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>
  2. Start via Compose:
    docker compose up -d

Potential container startup errors

  1. 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
  2. Slow or unreliable radio communication
    Ensure the container has sufficient CPU shares to process radio messages in time. Add --cap=sys_nice and tweak CPU settings in docker 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
  3. (Partly obsolete) cpu.rt_runtime_us == 0 errors in docker logs ccu
    Your host kernel has CONFIG_RT_GROUP_SCHED enabled 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

Container Usage

WebUI access

Point your browser to the container IP:

http://<IP-ADDRESS>/

Shell access

Either enable SSH in the CCU WebUI, or:

docker exec -it ccu /bin/sh

Updating to newer versions

Update 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.


Uninstallation

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 uninstall

This removes containers, networks, and related config files. After a reboot, only the data volume should remain.


Appendix

Additional install-docker.sh settings

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 for docker run.
    Default: (empty)

  • CCU_DOCKER_PULL_OPTIONS
    Additional options for docker pull.
    Default: (empty)

  • CCU_DOCKER_PULL_REFRESH
    Whether to run docker pull to refresh the image.
    Default: true

  • CCU_DOCKER_STOP_TIMEOUT
    Time (seconds) allowed to stop the container before Docker kills it.
    Default: 30

⚠️ **GitHub.com Fallback** ⚠️