Arcane Docker Install: Self-Hosted Container Manager

Step-by-step guide to install Arcane with Docker Compose. Covers basic setup, socket proxy security, OIDC authentication, reverse proxy config, and remote host management.

Arcane Docker Install: Self-Hosted Container Manager

I’ve been running Arcane on two of my servers for a few weeks now. It replaced Portainer on both, and I haven’t looked back. The whole thing runs on Go, which means it’s fast, light on memory, and doesn’t need a complicated runtime.

If you’re looking for a comparison with another newer Docker manager, check out my Arcane vs Dockhand article. But if you’ve already decided on Arcane and just want it running, this guide covers everything from basic install to socket proxy security.

What Arcane actually does

Arcane is a web-based Docker management UI. You get container management, compose stack editing, real-time logs, a web terminal, and GitOps all in one interface. It runs as a single container.

Arcane Docker Manager UI showing container list and compose editor

A few things that stood out to me after using it:

  • REST API that you can script against directly
  • CLI tool for terminal-based management alongside the web UI
  • GitOps built in, not as an afterthought. Point it at a repo and your stacks sync automatically
  • OIDC/SSO support for single sign-on
  • Remote host management via the arcane-headless agent
  • BSD-3-Clause license. Free, no paid tiers, no feature locks

The project has around 4,400 GitHub stars, 35 contributors, and has been actively developed since 2022. It’s not new software.

Prerequisites

Before you start, you need:

  • A Linux server (VPS or local machine). I recommend Hetzner for VPS hosting
  • Docker and Docker Compose installed
  • Basic terminal knowledge
Hetzner VPS DigitalOcean $100 Free Vultr $100 Free

Or use a Mini PC as home server.

Install Docker

If you don’t have Docker yet:

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-compose

Full walkthrough: Install Docker & Docker-compose for Ubuntu.

Install Arcane with Docker Compose

There are two ways to install Arcane. The convenience script is the fastest, but I prefer the compose method because you can see and control exactly what’s happening.

Quick install (convenience script)

If you want to get running in 30 seconds:

curl -fsSL https://getarcane.app/install.sh | bash

This pulls the image, generates secrets, and starts the container. Good for testing, but I wouldn’t use it for a permanent setup because you don’t control the compose file.

First, create a directory for Arcane:

mkdir -p /opt/arcane
cd /opt/arcane

Generate the secrets you’ll need. Run this command twice, once for ENCRYPTION_KEY and once for JWT_SECRET:

docker run --rm ghcr.io/getarcaneapp/arcane:latest /app/arcane generate secret

Copy both values. Now create your compose.yaml:

services:
  arcane:
    image: ghcr.io/getarcaneapp/arcane:latest
    container_name: arcane
    ports:
      - "3552:3552"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - arcane-data:/app/data
      - /opt/stacks:/opt/stacks
    environment:
      - APP_URL=http://localhost:3552
      - PUID=1000
      - PGID=1000
      - ENCRYPTION_KEY=your-generated-encryption-key
      - JWT_SECRET=your-generated-jwt-secret
    restart: unless-stopped
volumes:
  arcane-data:

Replace the ENCRYPTION_KEY and JWT_SECRET values with the ones you generated. Set APP_URL to your actual server address if you’re accessing it remotely.

Start it up:

docker compose up -d

Open http://your-server-ip:3552 in your browser. Default login credentials are arcane / arcane-admin. Change the password immediately.

Volume paths matter

If you want Arcane to manage existing compose projects on your server, mount the directory with matching paths inside and outside the container. For example, if your stacks live at /opt/stacks, mount it as /opt/stacks:/opt/stacks, NOT as /opt/stacks:/app/data/projects. Compose files use relative paths, and they’ll break if the mount point doesn’t match. You can also set the PROJECTS_DIRECTORY environment variable to tell Arcane where to look.

Hardening: Docker socket proxy

Mounting the Docker socket directly gives Arcane full control over your Docker daemon. That’s a security risk. If Arcane gets compromised somehow, an attacker has root-equivalent access to your host.

The fix is a socket proxy that filters which Docker API calls Arcane can make.

Why use a socket proxy?

The Docker socket (/var/run/docker.sock) is essentially a root-level API. Any container with access to it can create privileged containers, mount the host filesystem, or run arbitrary commands as root on the host.

A socket proxy sits between Arcane and the Docker daemon. It intercepts API calls and only allows the ones you’ve explicitly permitted. You get the management functionality without handing over the keys to the kingdom.

This setup is recommended for any internet-facing server. For a homelab behind a firewall, direct socket mounting is probably fine.

Here’s a compose setup with Tecnativa’s docker-socket-proxy:

services:
  arcane:
    image: ghcr.io/getarcaneapp/arcane:latest
    container_name: arcane
    ports:
      - "3552:3552"
    volumes:
      - arcane-data:/app/data
      - /opt/stacks:/opt/stacks
    environment:
      - APP_URL=http://localhost:3552
      - PUID=1000
      - PGID=1000
      - ENCRYPTION_KEY=your-generated-encryption-key
      - JWT_SECRET=your-generated-jwt-secret
      - DOCKER_HOST=tcp://docker-socket-proxy:2375
    depends_on:
      - docker-socket-proxy
    networks:
      - arcane-net
    restart: unless-stopped

  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy
    container_name: arcane-socket-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - CONTAINERS=1
      - IMAGES=1
      - NETWORKS=1
      - VOLUMES=1
      - SERVICES=1
      - TASKS=1
      - NODES=1
      - BUILD=1
      - EXEC=1
      - SYSTEM=1
      - INFO=1
      - VERSION=1
      - POST=1
      - DELETE=1
    networks:
      - arcane-net
    restart: unless-stopped

networks:
  arcane-net:
    driver: bridge

volumes:
  arcane-data:

Notice that Arcane no longer mounts the Docker socket directly. Instead, it connects to the proxy via DOCKER_HOST=tcp://docker-socket-proxy:2375. The socket is mounted read-only on the proxy container, and both containers sit on an internal bridge network.

The environment variables on the proxy control which Docker API endpoints are accessible. The list above is fairly permissive since Arcane needs most of them to function. You can tighten it further if you don’t need certain features.

Setting up OIDC/SSO

If you’re already running an identity provider like Authentik, Keycloak, or Authelia, you can hook Arcane into it for single sign-on.

Go to Settings > Security > OIDC Authentication in Arcane. Fill in your client ID, client secret, and issuer URL. The redirect URI is:

https://your-arcane-url/auth/oidc/callback

Save and test the connection. Users who authenticate via OIDC are auto-provisioned on first login.

Add these to your compose file:

environment:
  - OIDC_ENABLED=true
  - OIDC_CLIENT_ID=your-client-id
  - OIDC_CLIENT_SECRET=your-client-secret
  - OIDC_ISSUER_URL=https://your-idp.example.com
  - OIDC_ADMIN_CLAIM=groups
  - OIDC_ADMIN_VALUE=arcane-admins

OIDC_ADMIN_CLAIM and OIDC_ADMIN_VALUE let you auto-assign admin privileges based on a claim from your identity provider. So if a user belongs to the arcane-admins group, they get admin access automatically.

If you want to disable local password login entirely once OIDC is working, that’s configurable too.

Reverse proxy setup

You’ll want a reverse proxy in front of Arcane for SSL and a clean domain name. Arcane uses WebSockets for real-time updates, so your proxy config needs to support that.

server {
    listen 443 ssl http2;
    server_name arcane.yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3552;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

The key lines are proxy_http_version 1.1 and the Upgrade / Connection headers. Without them, WebSocket connections fail and the UI won’t get live updates.

If you’re already running Traefik (and you probably should be for Docker setups), add labels to your Arcane service:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.arcane.rule=Host(`arcane.yourdomain.com`)"
  - "traefik.http.routers.arcane.entrypoints=websecure"
  - "traefik.http.routers.arcane.tls.certresolver=letsencrypt"
  - "traefik.http.services.arcane.loadbalancer.server.port=3552"

Traefik handles WebSocket upgrade automatically. Full Traefik setup guide: How to use Traefik as a reverse proxy in Docker.

If you don’t want to expose ports at all, Cloudflare Tunnels work well. Point a tunnel at http://localhost:3552 and Cloudflare handles SSL and routing. WebSocket support is automatic.

This is what I use on my homelab since I don’t want to open any ports on my router.

Update the APP_URL environment variable in your compose file to match your actual domain (e.g., https://arcane.yourdomain.com).

Managing remote hosts

Arcane can manage Docker on other machines through the arcane-headless agent. This is useful if you have multiple servers but want one dashboard.

On the remote machine, deploy the agent:

services:
  arcane-agent:
    image: ghcr.io/getarcaneapp/arcane:latest
    container_name: arcane-agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - AGENT_MODE=true
      - AGENT_TOKEN=your-agent-token
      - MANAGER_API_URL=https://arcane.yourdomain.com
    restart: unless-stopped

Generate the AGENT_TOKEN on your main Arcane instance, then paste it here. The agent connects outbound to your main instance, so you don’t need to open any ports on the remote machine.

Environment variables reference

Here are the most useful environment variables you can set:

VariableDefaultWhat it does
APP_URLhttp://localhost:3552Public URL for the instance
PUID / PGID1000User/group ID for file permissions
ENCRYPTION_KEYnoneRequired. 32-byte key for encrypting sensitive data
JWT_SECRETnoneRequired. Secret for signing auth tokens
DOCKER_HOSTunix:///var/run/docker.sockDocker connection. Use tcp:// for socket proxy
DATABASE_URLSQLiteExternal PostgreSQL connection string
GPU_MONITORING_ENABLEDfalseEnable NVIDIA/AMD GPU stats
GPU_TYPEnonenvidia or amd
LOG_LEVELinfoLogging verbosity
UI_CONFIGURATION_DISABLEDfalseForce config via env vars only

Troubleshooting

Arcane can't see my existing compose stacks

This is almost always a volume mount path mismatch. If your compose files live at /opt/stacks/myapp/compose.yaml, mount that exact path:

volumes:
  - /opt/stacks:/opt/stacks

Not /opt/stacks:/some/other/path. The paths inside and outside the container must match. Also set PROJECTS_DIRECTORY=/opt/stacks in the environment.

WebSocket errors or UI not updating live

Your reverse proxy isn’t forwarding WebSocket connections. Make sure you have the upgrade headers set. For Nginx, you need:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Permission denied on Docker socket

Either add your user to the docker group (sudo usermod -aG docker $USER) or make sure the PUID/PGID values in the compose file match a user with Docker access.

Can't generate secrets

The secret generation command requires pulling the Arcane image first. If it fails, pull manually:

docker pull ghcr.io/getarcaneapp/arcane:latest
docker run --rm ghcr.io/getarcaneapp/arcane:latest /app/arcane generate secret

What I like and what’s missing

After a few weeks with Arcane, here’s where I’ve landed.

The GitOps integration is genuinely good. I keep my compose files in a private Git repo, and when I push changes, Arcane picks them up and redeploys. No webhook config, no CI pipeline needed. It just works.

The REST API is another strong point. I wrote a small script that checks container health and restarts anything that’s unhealthy. Took about 20 minutes because the API is straightforward.

What I wish it had: vulnerability scanning (Dockhand has this), scheduled auto-updates with rollback protection, and a file browser for containers. These aren’t dealbreakers, but they’d make Arcane the complete package.

If you want vulnerability scanning and some of those missing features, take a look at how to install Dockhand. There’s also UsulNet, a newer all-in-one Docker management platform that bundles Trivy scanning, backups, reverse proxy config, and multi-node orchestration into a single Go binary.