Running UniFi OS Server in Docker

unifi_os_startup .png

unifi_os_startup .png

The installer referenced in this article is outdated. Download links for the latest version of UniFi OS Server are available in the UniFi OS Server 5.0.6 – Download Links post.

Don't want to run this yourself? Unihosted offers fully managed, hosted UniFi OS Server — no Docker, no binwalk, no systemd wrangling required. Get started with Unihosted and have your UniFi OS Server running in minutes.

UniFi OS Server is Ubiquiti's powerful network management platform that orchestrates UniFi Network, UniFi Identity, UniFi Protect, and other services. While Ubiquiti officially distributes UniFi OS Server as a Podman image, we needed to run it in Docker for our infrastructure at Unihosted. This post details the technical journey of extracting, converting, and containerizing UniFi OS Server for Docker.

The Challenge

UniFi OS Server comes packaged as a binary installer that embeds a container image. The installer is designed for Podman, not Docker, and the image format is OCI (Open Container Initiative) rather than Docker's native format. Additionally, UniFi OS Server has several unique requirements:

  • Systemd dependency: The platform relies on systemd for service management
  • Privileged access: Requires elevated permissions for network configuration
  • Complex initialization: Multiple services need proper initialization and configuration
  • Persistent state: Extensive data directories that must survive container restarts

Step 1: Extracting the Base Image

The first challenge was extracting the container image from Ubiquiti's installer binary. The installer (unifi-os-server-download-506-x64) contains an embedded archive that we needed to extract.

Using Binwalk for Extraction

We used binwalk, a firmware analysis tool, to extract the embedded filesystem from the installer:

bash
binwalk --run-as=root -e unifi-os-server-download-506-x64

This extracts the contents to a directory (typically _unifi-os-server-download-506-x64.extracted/), revealing the embedded image.tar file containing the OCI-formatted container image.

Step 2: Converting OCI to Docker Format

The extracted image is in OCI format, which Docker can't directly load. We needed to convert it to Docker's format. While Docker and Podman share compatibility, the image format needed explicit conversion.

Podman as a Conversion Tool

Podman can handle both OCI and Docker formats, making it the perfect tool for conversion:

bash
# Load the OCI image into Podman
podman load -i image.tar

# Save it in Docker format
podman save --format docker-archive -o uosserver-0.0.54-docker.tar <image-name>

This creates a Docker-compatible image that can be loaded with docker load.

Step 3: Building the Docker Image

With the base image converted, we created a Dockerfile that extends it and adds our customizations:

dockerfile
FROM uosserver:0.0.54

ENV UOS_SERVER_VERSION="5.0.6"
ENV FIRMWARE_PLATFORM="linux-x64"

STOPSIGNAL SIGRTMIN+3

Key points:

  • STOPSIGNAL SIGRTMIN+3: This is systemd's shutdown signal, required for graceful service shutdown
  • Environment variables: Set the version and platform that UniFi OS Server expects

Step 4: Docker Compose Configuration

For production deployment, we use Docker Compose to manage the container with all necessary configurations:

yaml
services:
  unifi-os-server:
    image: unifi-os-server-dries:latest
    container_name: unifi-os-server
    privileged: true
    environment:
      - UOS_SYSTEM_IP=127.0.0.1
    volumes:
      - ./docker/persistent:/persistent
      - ./docker/var-log:/var/log
      - ./docker/data:/data
      - ./docker/srv:/srv
      - ./docker/var-lib-unifi:/var/lib/unifi
      - ./docker/var-lib-mongodb:/var/lib/mongodb
      - ./docker/etc-rabbitmq-ssl:/etc/rabbitmq/ssl
    ports:
      - 11443:443
      - 8080:8080
      - 8443:8443
      - 3478:3478/udp
      # ... additional ports for various services
    restart: unless-stopped

Key Configuration Points

Privileged Mode: Required for systemd and network configuration. While not ideal from a security perspective, it's necessary for UniFi OS Server's architecture.

Volume Mounts: Extensive persistence is required:

  • /data: Application data for all services (UID, ULP, UniFi Core, etc.)
  • /var/lib/unifi: UniFi Network configuration
  • /var/lib/mongodb: Database files
  • /var/log: All service logs
  • /persistent: Package manager state
  • /srv: Service-specific data

Port Mappings: UniFi OS Server exposes many ports:

  • 443: HTTPS management interface
  • 8080: HTTP management interface
  • 8443: UniFi Network controller
  • 3478/udp: STUN/TURN for WebRTC
  • And many more for various services

Architecture Insights

UniFi OS Server is a complex microservices architecture running multiple components:

  • UniFi Core: The core management service
  • UniFi Identity (UID): User identity and authentication
  • UniFi Link Platform (ULP): Service orchestration
  • UniFi Directory: Directory services
  • UCS Agent: Cloud services agent
  • MongoDB: Primary database
  • RabbitMQ: Message broker
  • PostgreSQL: Additional database backend
  • Nginx: Reverse proxy and web server

All these services are managed by systemd within the container, which is why we need privileged mode and systemd support.

Challenges and Solutions

Challenge 1: Systemd in Docker

Problem: Docker containers don't run systemd by default, but UniFi OS Server requires it.

Solution: Use a base image that includes systemd and run /sbin/init as PID 1. The container must be privileged to allow systemd to function properly.

Challenge 2: Network Interface Expectations

Problem: UniFi OS Server expects eth0 to exist, but Docker creates interfaces like tap0.

Solution: Create a macvlan interface alias from tap0 to eth0 in the container startup configuration.

Challenge 3: Persistent UUID

Problem: UniFi OS Server generates a UUID on first boot and expects it to persist.

Solution: Store the UUID in a persistent volume (/data/uos_uuid) and read it on subsequent starts.

Production Considerations

Security

Running in privileged mode is a security concern. Consider:

  • Network isolation
  • Firewall rules
  • Regular security updates
  • Monitoring and logging

Resource Requirements

UniFi OS Server is resource-intensive:

  • CPU: Multi-core recommended
  • Memory: At least 4GB, 8GB+ for production
  • Storage: Significant space needed for logs, databases, and firmware

Backup Strategy

Critical volumes to backup:

  • /var/lib/unifi: Network configuration
  • /var/lib/mongodb: Database
  • /data: All service data

Updates

Updating requires:

  1. Extracting the new base image from the latest installer
  2. Rebuilding the Docker image
  3. Testing in a non-production environment
  4. Careful migration of persistent data

Conclusion

Running UniFi OS Server in Docker required solving several technical challenges: extracting the embedded image, converting formats, handling systemd, and managing complex initialization. While the process is intricate, the result is a containerized UniFi OS Server that can be deployed, scaled, and managed like any other Docker service.

This approach enables us at Unihosted to provide UniFi OS Server as a managed service, with all the benefits of containerization: portability, version control, easy deployment, and infrastructure as code.


Have questions or want to share your experience running UniFi OS Server in containers? Reach out to us at unihosted.com.