Dockhand User Manual

Welcome to Dockhand, a modern, powerful Docker management application. This manual covers all features and functionality to help you get the most out of Dockhand.

Free vs Enterprise edition

In the free edition, all authenticated users have full admin access to all environments and features. There are no role restrictions - if you can log in, you can do everything.

The Enterprise edition adds Role-Based Access Control (RBAC), allowing you to define custom roles with specific permissions and restrict access to individual environments. See the Enterprise features section for details.

Quick start

Get Dockhand running in minutes with Docker:

Docker
docker run -d \
  --name dockhand \
  --restart unless-stopped \
  -p 3000:3000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v dockhand_data:/app/data \
  fnsys/dockhand:v1.0.0

Or using Docker Compose:

docker-compose.yml
services:
  dockhand:
    image: fnsys/dockhand:v1.0.0
    container_name: dockhand
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - dockhand_data:/app/data

volumes:
  dockhand_data:

Then open http://localhost:3000 in your browser.

First-time setup

On first launch, authentication is disabled. Go to Settings > Authentication to enable authentication and create your first admin user.

Docker socket permissions

Dockhand needs access to Docker to manage containers. By default, the Dockhand container runs as a non-root user, which may not have permission to access the socket on your host system.

If you see a "permission denied" error when trying to add your local environment, you'll need to configure socket access. Here are the options:

1

Match the Docker group GID

Find your host's Docker group ID and run Dockhand with that group:

Bash
# Find the Docker group ID on your host (Linux)
stat -c '%g' /var/run/docker.sock
# On macOS, use: stat -f '%g' /var/run/docker.sock
# Example output: 999

# Run Dockhand with the matching group
docker run -d \
  --name dockhand \
  --restart unless-stopped \
  --group-add 999 \
  -p 3000:3000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v dockhand_data:/app/data \
  fnsys/dockhand:v1.0.0

Or using Docker Compose:

docker-compose.yml
services:
  dockhand:
    image: fnsys/dockhand:v1.0.0
    container_name: dockhand
    restart: unless-stopped
    group_add:
      - "999"  # Replace with your host's Docker GID
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - dockhand_data:/app/data

volumes:
  dockhand_data:
2

Run as root user

Simplest

Running as root (0:0) bypasses all permission checks. This is the simplest solution but gives the container full root privileges:

Docker
docker run -d \
  --name dockhand \
  --restart unless-stopped \
  --user 0:0 \
  -p 3000:3000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v dockhand_data:/app/data \
  fnsys/dockhand:v1.0.0

Or using Docker Compose:

docker-compose.yml
services:
  dockhand:
    image: fnsys/dockhand:v1.0.0
    container_name: dockhand
    restart: unless-stopped
    user: "0:0"
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - dockhand_data:/app/data

volumes:
  dockhand_data:
Security consideration

Running as root is convenient but less secure. Anyone with access to Dockhand can potentially access the Docker daemon with full privileges. Use Option 4 in production environments where security is a concern.

3

Change socket permissions on host

Not recommended

You can make the Docker socket world-readable, but this exposes it to all users on the host:

Bash
# NOT RECOMMENDED - makes socket accessible to everyone
sudo chmod 666 /var/run/docker.sock
Security risk

This change affects all processes on the host, not just Dockhand. Any user or container can now access Docker. The permission resets on Docker daemon restart.

4

Docker socket proxy

Most secure

If you want truly secure access, place a proxy between Dockhand and the actual Docker socket. This filters which API calls are allowed. A popular tool for this is tecnativa/docker-socket-proxy.

Docker Compose
services:
  socket-proxy:
    image: tecnativa/docker-socket-proxy
    container_name: socket-proxy
    restart: unless-stopped
    environment:
      # Required for Dockhand core functionality
      - CONTAINERS=1
      - IMAGES=1
      - NETWORKS=1
      - VOLUMES=1
      - EVENTS=1
      - POST=1
      - DELETE=1
      # Optional: enable for terminal access
      # - EXEC=1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - socket-proxy

  dockhand:
    image: fnsys/dockhand:v1.0.0
    container_name: dockhand
    restart: unless-stopped
    depends_on:
      - socket-proxy
    ports:
      - "3000:3000"
    volumes:
      - dockhand_data:/app/data
    networks:
      - socket-proxy
      - default

networks:
  socket-proxy:
    internal: true

volumes:
  dockhand_data:

See the full list of environment variables for additional options.

After starting the stack, configure Dockhand to use the proxy:

  1. Go to Settings > Environments
  2. Add a new environment or edit the default one
  3. Set connection type to Direct
  4. Set the host to tcp://socket-proxy:2375
  5. Save the environment
Socket proxy benefits

The proxy acts as a firewall for the Docker API. It allows only necessary commands (list, start, stop containers) but can block dangerous ones (docker run --privileged, system commands). Dockhand connects to the proxy via a private Docker network, isolated from the raw socket.

Socket proxy is not a silver bullet

The socket proxy container itself requires elevated privileges to access the Docker socket (typically --privileged or additional AppArmor/SELinux rules), which transfers some security risk to the proxy container.

More importantly: even with a socket proxy, anyone who gains access to Dockhand still has significant capabilities — starting/stopping containers, deleting volumes, pulling images, viewing logs, and more. The proxy limits the most dangerous operations but doesn't make Dockhand "safe to expose publicly".

Always restrict access to Dockhand itself using a reverse proxy with authentication, VPN (Tailscale/WireGuard), SSO/OIDC, or network segmentation. Treat Dockhand as an admin interface that should never be directly exposed to the internet.

Recommendations by environment

Home lab or private server behind a VPN (Tailscale/WireGuard):

Option 1 (GID matching) or Option 2 (root) is acceptable. The risk is manageable assuming your network is secure and you trust the Dockhand application code.

Public-facing server or production environment:

Consider using a Socket Proxy (Option 4) or restricting access via a VPN.

Security summary

Method Container User Socket Access Security Level Risk
Option 1 (GID) Non-root Direct Low/Medium Root-equivalent if app is exploited
Option 2 (Root) Root Direct None Immediate root if app is exploited
Option 3 (chmod) Any Direct None All host users can access Docker
Option 4 (Proxy) Non-root Filtered Higher* Blocks dangerous API calls, but depends on enabled endpoints

* Higher than direct socket access, but actual security depends on proxy configuration (which API endpoints are enabled) and container hardening.

Platform notes

Windows

Docker on Windows uses a named pipe instead of a Unix socket. In your volume mount, replace the socket path with:

-v //./pipe/docker_engine://./pipe/docker_engine

The permission options above (GID matching, chmod) do not apply to Windows.

Deployment examples

Behind a reverse proxy (Traefik)

When running behind Traefik or another reverse proxy, you don't need to expose ports directly:

Docker Compose
services:
  dockhand:
    image: fnsys/dockhand:v1.0.0
    container_name: dockhand
    restart: unless-stopped
    user: "0:0"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - dockhand_data:/app/data
    networks:
      - proxy  # Must match your Traefik network
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dockhand.rule=Host(`dockhand.example.com`)"
      - "traefik.http.routers.dockhand.entrypoints=websecure"
      - "traefik.http.routers.dockhand.tls=true"
      - "traefik.http.routers.dockhand.tls.certresolver=letsencrypt"
      - "traefik.http.services.dockhand.loadbalancer.server.port=3000"
      - "traefik.docker.network=proxy"  # Required if container has multiple networks

networks:
  proxy:
    external: true  # Assumes Traefik network already exists

volumes:
  dockhand_data:

With Nginx reverse proxy

Example Nginx configuration for proxying to Dockhand:

Nginx
server {
    listen 443 ssl http2;
    server_name dockhand.example.com;

    ssl_certificate /etc/ssl/certs/dockhand.crt;
    ssl_certificate_key /etc/ssl/private/dockhand.key;

    location / {
        proxy_pass http://localhost:3000;
        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;
    }
}
WebSocket support required

Dockhand uses WebSockets for the terminal and real-time updates. Make sure your reverse proxy is configured to handle WebSocket connections (the Upgrade and Connection headers).

With Tailscale (VPN-only access)

The simplest and usually most secure approach: Traefik listens on 80/443, but ports are only accessible within your Tailnet (no public port exposure on the host).

Docker Compose
services:
  tailscale:
    image: tailscale/tailscale:latest
    hostname: homelab-gw
    environment:
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
    volumes:
      - tailscale_state:/var/lib/tailscale
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - net_admin
      - sys_module
    restart: unless-stopped

  socket-proxy:
    image: tecnativa/docker-socket-proxy
    environment:
      - CONTAINERS=1
      - SERVICES=1
      - NETWORKS=1
      - EVENTS=1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks: [socket_proxy]
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true

  traefik:
    image: traefik:v3
    network_mode: service:tailscale
    depends_on: [socket-proxy]
    command:
      - --api.dashboard=true
      - --providers.docker=true
      - --providers.docker.endpoint=tcp://socket-proxy:2375
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
    volumes:
      - traefik_data:/data
    restart: unless-stopped

  dockhand:
    image: fnsys/dockhand:v1.0.0
    labels:
      - traefik.enable=true
      - traefik.http.routers.dockhand.rule=Host(`dockhand.homelab-gw.ts.net`)
      - traefik.http.routers.dockhand.entrypoints=websecure
      - traefik.http.routers.dockhand.tls=true
      - traefik.http.services.dockhand.loadbalancer.server.port=3000
    networks: [default]
    restart: unless-stopped
    volumes:
      - dockhand_data:/app/data

networks:
  socket_proxy:
    internal: true

volumes:
  tailscale_state:
  traefik_data:
  dockhand_data:

This works because Traefik "inherits" the Tailscale network via network_mode: service:tailscale, so ports 80/443 are reachable at the Tailscale address (MagicDNS) but not exposed publicly.

Using PostgreSQL database

Dockhand can also use PostgreSQL instead of the default SQLite:

Docker
docker run -d \
  --name dockhand \
  --restart unless-stopped \
  --user 0:0 \
  -p 3000:3000 \
  -e DATABASE_URL=postgres://user:password@postgres-host:5432/dockhand \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v dockhand_data:/app/data \
  fnsys/dockhand:v1.0.0

The database schema is created automatically on first run. Just ensure the database exists and the user has sufficient privileges.

No automatic migration

Switching from SQLite (default) to PostgreSQL does not migrate existing data. You will start with a fresh database.

Managing remote Docker hosts

Dockhand can manage Docker hosts beyond your local machine. There are several ways to connect to remote environments:

Connection Type Use Case Requirements
Local socket Same machine as Dockhand Docker socket mounted
Direct TCP Remote Docker with exposed API Docker API on port 2375/2376
Hawser Standard LAN/homelab with static IPs Hawser agent on remote host
Hawser Edge VPS, NAT, dynamic IP, firewalled hosts Hawser agent (outbound only)

Hawser is a lightweight agent that enables secure remote Docker management without exposing the Docker API directly. It's especially useful for:

  • Hosts behind NAT or firewalls (Edge mode - no inbound ports required)
  • VPS or cloud instances with dynamic IPs
  • Secure access without exposing Docker TCP port
  • Homelab environments across different networks

See the Hawser section for detailed setup instructions.

System requirements

Component Requirement
Docker Engine 20.10 or later
Docker API 1.41 or later
Memory 512 MB minimum, 1 GB recommended
Browser Chrome, Firefox, Safari, Edge (latest versions)
Database SQLite (default) or PostgreSQL 14+

Dashboard

The dashboard provides a real-time overview of all your Docker environments. Each environment is displayed as a tile that can be resized and repositioned to suit your workflow.

Environment tiles

Each environment tile displays key information at a glance:

  • Header - Environment name, icon, and connection status
  • Container counts - Running, stopped, and total containers
  • Resource metrics - CPU and memory usage with progress bars
  • Health status - Warning banner for unhealthy or restarting containers
  • Activity summary - Today's events and recent activity
  • Top containers - Containers sorted by CPU usage (larger tiles)

Status indicators

Tiles display status icons in the header:

Icon Status Description
Shield (green glow) Scanner enabled Vulnerability scanning is active for this environment
Activity (amber glow) Activity collection Container events are being tracked
WifiOff (red) Offline Environment is unreachable

Tile sizing

Tiles can be resized to show more or less information. Drag the corner of any tile to resize it.

Size Content
1x1 (Compact) Header, container counts, CPU/Memory bars
2x1 (Wide compact) Same as 1x1 with more horizontal space
1x2 (Standard) Container stats, health banner, resource metrics, resources summary
1x3 (Detailed) All 1x2 content + recent events list (8 items)
1x4+ (Extra tall) All 1x3 content + top containers by CPU
2x2 (Square) Two columns: stats on left, top containers on right
2x3 (Wide tall) Two columns: stats + events, containers + charts
2x4+ (Full) Two columns with CPU/Memory charts and disk usage breakdown

Layout management

The dashboard provides several ways to organize your tiles:

Auto-layout presets

Use the dropdown in the header to quickly apply preset layouts:

  • Compact - All tiles at 1x1 size
  • Standard - All tiles at 1x2 size
  • Detailed - All tiles at 1x3 size
  • Full - All tiles at 2x3 size

Drag and drop

Drag tiles by their header to reposition them. The layout is automatically saved to your browser's local storage.

Label filtering

If you've assigned labels to environments, you can filter the dashboard to show only environments with specific labels. Click the label pills at the top of the dashboard to toggle filtering.

Real-time updates

Dashboard data is streamed in real-time using Server-Sent Events (SSE). Metrics update every 10 seconds, and container events appear instantly.

Containers

The Containers page provides comprehensive management of all Docker containers across your environments.

List view

The container list displays all containers with sortable columns:

Column Description
Name Container name (click to inspect)
Image Image tag used by the container
State Running, Stopped, Paused, Restarting, Created
Health Health check status (if configured)
Uptime Time since container started/stopped
CPU % Real-time CPU usage percentage
Memory Current memory usage
Network I/O Received / Sent bytes
Disk I/O Read / Write bytes
IP Address Container's IP address
Ports Published port mappings (host:container)
Stack Compose project name (if part of a stack)

Search and sort

Use the search box to filter containers by name, image, or stack. Click column headers to sort. Press Esc to clear the search.

Bulk operations

Select multiple containers using the checkboxes, then use the bulk action buttons:

  • Start - Start all selected stopped containers
  • Stop - Stop all selected running containers
  • Restart - Restart all selected containers
  • Remove - Delete all selected containers

Container actions

Each container row has action buttons for common operations:

Action Description
Start Start a stopped container
Stop Stop a running container (with confirmation)
Pause Pause a running container
Restart Restart a container (with confirmation)
Inspect View detailed container configuration
Browse Files Open file browser (running containers only)
Edit Edit container configuration
Logs Open logs panel
Terminal Open interactive shell
Delete Remove container (with confirmation)

Creating containers

Click the Create container button to launch a new container. The modal provides all configuration options:

Basic settings

  • Image - Select from local images or enter image:tag to pull
  • Name - Container name (auto-generated if empty)
  • Command - Override the default command
  • Working directory - Set the working directory

Port mappings

Map container ports to host ports. Format: host_port:container_port/protocol

Docker documentation

Port publishing binds container ports to host interfaces. See Docker networking documentation for details on port mapping and network modes.

Volume mounts

Mount host directories or named volumes into the container:

  • Bind mount - /host/path:/container/path
  • Named volume - volume_name:/container/path
  • Read-only - Append :ro for read-only access

Environment variables

Set environment variables as key-value pairs. Sensitive values are masked in the UI.

Network

Select the network mode:

  • bridge (default) - Container gets its own IP on a bridge network
  • host - Container shares the host's network stack
  • none - No networking
  • Custom network - Connect to a user-defined network

Restart policy

Policy Behavior
no Never restart automatically
always Always restart when stopped
unless-stopped Restart unless manually stopped
on-failure Restart only on non-zero exit code

Resource limits

  • CPU limit - Maximum CPU cores (e.g., 0.5 for half a core)
  • Memory limit - Maximum memory (e.g., 512m, 1g)

Logs viewer

The logs viewer provides real-time streaming of container logs with ANSI color support.

Features

  • Real-time streaming - Logs appear instantly via Server-Sent Events
  • ANSI color rendering - Full color support for formatted output
  • Pause/Resume - Toggle streaming to freeze the view
  • Auto-scroll - Automatically scroll to the latest logs
  • Download - Export logs as a text file
  • Font size - Adjust between 10-18px

Connection status

The status indicator shows the current connection state:

  • Live (green pulse) - Streaming active
  • Connecting (yellow) - Establishing connection
  • Disconnected (red) - Connection lost, will retry
  • Paused (amber) - Streaming manually paused
Log buffer size

The default log buffer is 500 KB per panel. You can adjust this in Settings > General > Log buffer size. Larger buffers may impact browser performance.

Terminal

Open an interactive terminal session inside a running container.

Configuration

  • Shell - Select bash, sh, zsh, or ash
  • User - Run as root, nobody, or container default
  • Font size - Adjust terminal font size

Keyboard shortcuts

  • Cmd + L - Clear terminal
  • Cmd + C - Copy selection
  • Cmd + V - Paste

File browser

Browse and manage files inside running containers.

Features

  • Navigation - Browse directories with breadcrumb trail
  • Download - Download files or directories as tar archive
  • Upload - Upload files to the container
  • File info - View file sizes, types, and permissions

Auto-update

Configure automatic image updates for containers to keep them running the latest version.

Schedule options

  • Daily - Update once per day at a specific time
  • Weekly - Update on a specific day and time
  • Custom - Use a cron expression for precise scheduling

Vulnerability criteria

When vulnerability scanning is enabled, you can block updates based on scan results:

Criteria Behavior
Never block Always update regardless of vulnerabilities
Any Block if new image has any vulnerabilities
Critical or High Block if critical or high severity vulnerabilities found
Critical only Block only for critical severity vulnerabilities
More than current Block if new image has more total vulnerabilities than current
Auto-update process

Auto-update pulls the latest image, stops the current container, and creates a new container with the same configuration. This causes brief downtime. For zero-downtime updates, use Docker Compose with rolling update strategies.

Compose stacks

Manage Docker Compose stacks for multi-container applications. Dockhand supports both manually created stacks and stacks deployed from Git repositories.

Stack types

Type Badge Description
Internal Blue (FileCode) Created directly in Dockhand with YAML editor
Git Stack Purple (GitBranch) Synced from a Git repository with auto-update
External Gray (ExternalLink) Created outside Dockhand (e.g., via CLI)

Creating stacks

Click Create stack to open the YAML editor:

  1. Enter a stack name (becomes the Compose project name)
  2. Write or paste your docker-compose.yml content
  3. Optionally check "Deploy immediately" to start the stack
  4. Click Create

Git integration

Deploy stacks directly from Git repositories with automatic synchronization.

Git Repository
GitHub, GitLab, etc.
git pull
Dockhand
sync & compare
compose up
Docker
deploy stack

Triggers: Scheduled auto-sync • Webhook from CI/CD • Manual deploy button

Configuration

  • Repository - Select from configured Git repositories or add a new one
  • Branch - Target branch to track
  • Compose file path - Path to the compose file (default: docker-compose.yml)
  • Auto-sync - Enable automatic sync on a schedule
  • Schedule - Cron expression for auto-sync timing

Deployment behavior

Git stacks use intelligent deployment:

  • Only redeploys when the Git commit changes (detected via git pull)
  • Uses docker compose up -d --remove-orphans which only recreates changed services
  • Manual "Deploy" button forces redeployment regardless of changes

Webhooks

Trigger stack deployments from external services like GitHub, GitLab, or CI/CD pipelines.

GitHub / GitLab
push event
POST webhook
Dockhand
verify & sync
compose up
Docker
deploy stack

Push to repo → webhook triggers → Dockhand pulls changes → deploys updated stack

Webhook URL

Each Git stack gets a unique webhook URL:

https://your-dockhand.com/api/git/stacks/{id}/webhook

Supported methods

  • GET - Simple trigger (for testing)
  • POST - Standard webhook with optional signature verification

Webhook secret

For security, configure a webhook secret. The request signature is validated using HMAC-SHA256 in the X-Hub-Signature-256 header (GitHub compatible).

GitHub integration

In your GitHub repository, go to Settings > Webhooks > Add webhook. Paste the webhook URL, set content type to application/json, and enter your secret.

Images

The Images page shows all Docker images on the selected environment, grouped by repository.

Image actions

Action Description
Run Create a new container from this image
Scan Scan for vulnerabilities (if scanner configured)
Tag Add a new tag to this image
Push Push to a configured registry
Export Download as tar/tar.gz archive
History View image layer history
Delete Remove the image

Pulling images

Click Pull image to download a new image:

  1. Optionally select a registry (default: Docker Hub)
  2. Enter the image name (e.g., nginx, redis)
  3. Enter the tag (e.g., latest, alpine)
  4. Click Pull

Progress is shown layer-by-layer with download percentages.

Vulnerability scanning

Dockhand integrates with Grype and Trivy vulnerability scanners to identify security issues in your images.

Severity levels

Severity Color Description
Critical Red Severe vulnerabilities requiring immediate attention
High Orange Important vulnerabilities to fix soon
Medium Yellow Moderate risk vulnerabilities
Low Blue Minor vulnerabilities

Export formats

Scan results can be exported in multiple formats:

  • Markdown - Human-readable report
  • CSV - Spreadsheet format for analysis
  • JSON - Raw data for automation

Scan caching

Scan results are cached by image SHA256. Re-scanning the same image version returns cached results unless you force a fresh scan.

Auto-scan on pull

Enable "Scan on pull" in environment settings to automatically scan images when they're pulled. This ensures all new images are checked for vulnerabilities.

Registry operations

Pushing images

Push images to configured registries. Select the target registry and optionally specify a new tag.

Image history

View the layer-by-layer build history of an image, including:

  • Layer size
  • Creation timestamp
  • Command that created the layer

Volumes

Manage Docker volumes for persistent data storage.

Volume actions

  • Browse - Open volume browser (uses helper container)
  • Clone - Create a copy of volume configuration
  • Inspect - View detailed volume information
  • Export - Download volume contents as tar archive
  • Delete - Remove the volume (fails if in use)

Volume browser

Browse the contents of Docker volumes using a helper container.

How it works

Volume browsing uses a busybox:latest helper container that mounts the volume read-only. The container is automatically pulled if not present and removed when you close the browser.

Networks

Manage Docker networks for container communication.

Network drivers

Driver Description
bridge Default network for standalone containers
host Container uses host's network stack
overlay Multi-host networking (Swarm mode)
macvlan Assign MAC address for direct network access
none No networking

Creating networks

Configure:

  • Name - Network name
  • Driver - Network driver type
  • Subnet - CIDR notation (e.g., 172.20.0.0/16)
  • Gateway - Gateway IP address
  • Internal - Restrict external access
  • Attachable - Allow manual container attachment

Connecting containers

Use the "Connect container" action to attach containers to a network with optional:

  • Aliases - DNS aliases for the container on this network
  • IPv4 address - Specific IP address assignment
Protected networks

The default bridge, host, and none networks cannot be deleted. They are marked with a "Built-in" badge.

Registry browser

Browse and search Docker registries to discover and pull images.

Features

  • Search across configured registries
  • View available tags for each image
  • Pull images directly from search results
  • View image details and manifests
Registry configuration

Configure registries in Settings > Registries. Private registries require authentication credentials.

Activity log

Track all Docker container events across your environments in real-time.

Event types

Event Icon Description
create + Container created
start Play (green) Container started
stop Stop (red) Container stopped
die Skull Container exited
kill X Container killed
restart Refresh Container restarted
pause Pause Container paused
unpause Play Container unpaused
oom Alert Out of memory
health_status Heart Health check result

Filtering

Filter the activity log by:

  • Container name - Text search
  • Event type - Select specific event types
  • Environment - Filter by environment
  • Labels - Filter by environment labels
  • Date range - Presets or custom range
Enable activity collection

Activity collection must be enabled per-environment in Settings > Environments. The dashboard tile shows an amber "Activity" icon when collection is active.

Schedules

View and manage all scheduled jobs in one place.

Schedule types

Type Description
Container auto-update Automatic image updates for containers
Git stack sync Automatic sync and deploy from Git repositories
System cleanup Built-in cleanup jobs (schedule execution logs, container events)

Schedule management

  • Enable/Disable - Toggle schedule without deleting
  • Last run - When the schedule last executed
  • Next run - Calculated next execution time
  • Delete - Remove the schedule

System schedules

Dockhand includes built-in cleanup schedules that run automatically:

Job Description Default retention
Schedule execution cleanup Removes historical logs from auto-update and Git sync executions, including success/failure status and error messages 30 days
Container event cleanup Removes old container activity events (start, stop, restart, die) from the activity feed and dashboard timeline 7 days

Configure retention periods in Settings > General > Cleanup jobs.

Hawser remote agent

Hawser is a lightweight Go agent that enables Dockhand to manage Docker hosts in various network configurations, including hosts behind NAT, firewalls, or with dynamic IPs.

Connection modes

Hawser supports two operational modes:

Mode Use Case How It Works
Standard LAN, homelab, static IPs Agent listens, Dockhand connects to it
Edge VPS, NAT, dynamic IP, firewalls Agent connects outbound to Dockhand via WebSocket
1

Standard mode

Dockhand connects directly to the Hawser agent running on your Docker host. The agent exposes an HTTP API that proxies requests to the local Docker socket.

Dockhand
HTTP
Hawser Agent
:2376
Socket
Docker
Pros
  • Simple setup - just run the agent
  • Lower latency (direct connection)
  • Works on any network with IP connectivity
  • Optional TLS encryption
Cons
  • Requires inbound port access to Docker host
  • Need static IP or DNS for the agent
  • Firewall rules may be needed
2

Edge mode

The Hawser agent initiates an outbound WebSocket connection to Dockhand. All communication flows through this persistent connection - no inbound ports required on the Docker host.

Browser
HTTP
Dockhand
WebSocket
Hawser Agent
outbound
Socket
Docker
Pros
  • No inbound ports required
  • Works behind NAT, firewalls, dynamic IPs
  • Perfect for VPS and cloud instances
  • Auto-reconnect with exponential backoff
Cons
  • Dockhand must be publicly accessible (or via VPN)
  • Slightly higher latency (WebSocket overhead)
  • Token authentication is mandatory

Installation

Quick install script

The recommended way to install Hawser on Linux:

Bash
curl -fsSL https://raw.githubusercontent.com/Finsys/hawser/main/scripts/install.sh | bash

This script:

  • Detects OS and architecture (Linux amd64/arm64)
  • Downloads the latest release from GitHub
  • Installs to /usr/local/bin/hawser
  • Creates config directory at /etc/hawser/
  • Installs systemd service (or OpenRC on Alpine)

Docker installation

Standard mode:

Docker
docker run -d \
  --name hawser \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -p 2376:2376 \
  -e TOKEN=your-secret-token \
  ghcr.io/finsys/hawser:latest

Edge mode:

Docker
docker run -d \
  --name hawser \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect \
  -e TOKEN=your-agent-token \
  -e AGENT_NAME=my-server \
  ghcr.io/finsys/hawser:latest

Systemd service

Create /etc/systemd/system/hawser.service:

systemd
[Unit]
Description=Hawser - Remote Docker Agent for Dockhand
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service

[Service]
Type=simple
ExecStart=/usr/local/bin/hawser
Restart=always
RestartSec=10
EnvironmentFile=/etc/hawser/config

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable --now hawser

Configuration

Configure Hawser using environment variables or a config file at /etc/hawser/config:

Standard mode config

/etc/hawser/config
# Standard Mode Configuration
DOCKER_SOCKET=/var/run/docker.sock
PORT=2376
TOKEN=your-secret-token
AGENT_NAME=my-server
LOG_LEVEL=info

# Optional TLS
# TLS_CERT=/etc/hawser/server.crt
# TLS_KEY=/etc/hawser/server.key

Edge mode config

/etc/hawser/config
# Edge Mode Configuration
DOCKER_SOCKET=/var/run/docker.sock
DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect
TOKEN=your-agent-token-from-dockhand
AGENT_NAME=my-server
LOG_LEVEL=info

# Connection settings
HEARTBEAT_INTERVAL=30
RECONNECT_DELAY=1
MAX_RECONNECT_DELAY=60

Environment variables reference

Variable Default Mode Description
DOCKHAND_SERVER_URL - Edge WebSocket URL for Dockhand connection
TOKEN - Both Authentication token
PORT 2376 Standard HTTP server port
DOCKER_SOCKET /var/run/docker.sock Both Docker socket path
AGENT_NAME hostname Both Human-readable agent name
LOG_LEVEL info Both debug, info, warn, error
TLS_CERT - Standard TLS certificate path
TLS_KEY - Standard TLS private key path
CA_CERT - Edge CA certificate path (for self-signed Dockhand)
HEARTBEAT_INTERVAL 30 Edge Heartbeat interval in seconds

TLS configuration

TLS certificate handling differs based on which side initiates the connection:

Mode Connection direction TLS config location
Standard Dockhand → Hawser Dockhand UI (CA cert for self-signed)
Edge Hawser → Dockhand Hawser agent config (CA cert for self-signed Dockhand)
Standard mode TLS

When Hawser uses a self-signed TLS certificate, configure the CA certificate in Dockhand:

  1. Go to Settings > Environments
  2. Edit the Hawser Standard environment
  3. Set protocol to HTTPS
  4. Paste the CA certificate in the CA certificate field
  5. Optionally enable Skip TLS verification for testing (insecure)
Edge mode TLS

When Dockhand uses a self-signed TLS certificate, configure the CA certificate on the Hawser agent:

/etc/hawser/config
# Edge mode with self-signed Dockhand certificate
DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect
TOKEN=your-agent-token
CA_CERT=/etc/hawser/dockhand-ca.pem

# Or skip verification (insecure, for testing only)
# TLS_SKIP_VERIFY=true
Why is TLS configured on different sides?

The CA certificate must be on the client side to verify the server's identity. In Standard mode, Dockhand connects to Hawser (Dockhand is client). In Edge mode, Hawser connects to Dockhand (Hawser is client).

Token management

Edge mode requires tokens generated in Dockhand:

  1. Go to Settings > Environments
  2. Create or edit an environment with "Hawser - Edge" connection type
  3. Click Generate Token
  4. Copy the token immediately (shown only once)
  5. Configure Hawser on your Docker host with this token
Token security

Tokens are stored as Argon2id hashes in the database. The full token is shown only once at generation time. If lost, you must generate a new token.

Troubleshooting

Common issues

Issue Cause Solution
"Unauthorized" error Token mismatch Verify token matches between agent and Dockhand
"Edge agent not connected" Agent not running Start agent, check DOCKHAND_SERVER_URL
"Docker socket not found" Wrong socket path Set DOCKER_SOCKET=/var/run/docker.sock
Connection timeout Network/firewall Check firewall rules, WebSocket support

Debug mode

Enable detailed logging:

LOG_LEVEL=debug hawser

Check logs

# Systemd
sudo journalctl -u hawser -f

# Docker
docker logs -f hawser

Settings

Configure Dockhand behavior, environments, authentication, and integrations.

General settings

Setting Default Description
Show stopped containers On Include stopped containers in lists
Time format 24-hour 12-hour or 24-hour time display
Date format DD.MM.YYYY Date display format
Download format tar Format for file exports (tar or tar.gz)
Confirm destructive actions On Show confirmations before delete operations
Log buffer size 500 KB Maximum log buffer per panel (100-5000 KB)

Vulnerability scanner defaults

Configure default CLI arguments for vulnerability scanners. These settings allow you to adjust scanner behavior if Trivy or Grype CLI options change in future versions, or to add custom flags for your environment:

  • Grype CLI args - Default: -o json -v {image}
  • Trivy CLI args - Default: image --format json {image}

The {image} placeholder is replaced with the actual image name at scan time.

Cleanup jobs

Configure automatic cleanup of old data to prevent database growth:

Job What it cleans Default retention
Schedule execution cleanup Removes historical logs from auto-update and Git sync executions. These logs track when scheduled tasks ran, their success/failure status, and any error messages. Older logs are typically not needed once reviewed. 30 days
Container event cleanup Removes old container activity events (start, stop, restart, die, etc.) from the activity feed and dashboard. These events are collected from Docker and stored for the activity timeline. High-traffic environments can generate thousands of events daily. 7 days

Each cleanup job can be enabled/disabled independently with configurable retention periods (1-365 days). Jobs run automatically on a daily schedule.

Environments

Manage Docker environment connections.

Connection types

Type Description Use Case
Unix Socket Local Docker socket Dockhand on same host as Docker
Direct (HTTP/HTTPS) Remote Docker API Docker with exposed port
Hawser Standard Hawser agent listens LAN with static IPs
Hawser Edge Hawser agent connects out VPS, NAT, dynamic IPs

Environment options

  • Name - Display name for the environment
  • Icon - Custom icon from icon library
  • Labels - Tags for filtering (with colors)
  • Default environment - Selected by default on page load
  • Collect metrics - Enable CPU/memory monitoring
  • Collect activity - Track container events
  • Highlight changes - Visual indicators for stat changes

Vulnerability scanning

Per-environment scanner configuration:

  • Scanner - None, Grype, Trivy, or Both
  • Scan on pull - Auto-scan pulled images
  • Custom CLI args - Override default scanner arguments

Registries

Configure Docker registries for image operations.

  • Name - Display name
  • URL - Registry endpoint
  • Username/Password - Authentication credentials
  • Default - Set as default for pull operations

Git

Manage Git credentials and repositories for stack deployment.

Credentials

  • SSH keys - For SSH authentication
  • HTTPS credentials - Username/password or token

Repositories

  • URL - Git repository URL
  • Branch - Default branch to track
  • Credential - Link to saved credential

Config sets

Config sets are reusable configuration templates that can be applied when creating containers. They help maintain consistency and save time when deploying multiple containers with similar configurations.

What's included in a config set

  • Environment variables - Predefined key-value pairs
  • Labels - Container labels for organization and filtering
  • Port mappings - Common port configurations
  • Volume mounts - Standard volume configurations
  • Network mode - Network settings (bridge, host, etc.)
  • Restart policy - Container restart behavior

Using config sets

  1. Go to Settings > Config sets
  2. Click Add config set
  3. Enter a name and configure the desired options
  4. Save the config set
  5. When creating a new container, select the config set from the dropdown to pre-fill values
Config sets are templates

Values from config sets are copied when creating a container. Changes to a config set won't affect existing containers.

Notifications

Configure notification channels for alerts.

Channel types

  • SMTP - Email notifications via SMTP server
  • Apprise - Webhooks for Discord, Slack, Telegram, ntfy, Gotify, Pushover, etc.

Event types

Configure which events trigger notifications:

  • Container events - start, stop, unhealthy, OOM
  • Auto-update events - success, failed, blocked
  • Git stack events - sync success, failed, skipped
  • Stack events - deployed, failed
  • Security events - vulnerabilities found
  • System events - environment offline, disk warning

Authentication

Configure user authentication and access control.

General settings

  • Enable authentication - Toggle auth for the application
  • Session timeout - Session expiration (1-7 days)

Local users

Create and manage local user accounts:

  • Username, display name, email
  • Password (Argon2id hashed)
  • Admin role toggle
  • Avatar upload
  • Enable/disable account

OIDC/SSO

Configure Single Sign-On with OpenID Connect providers.

Supported providers

  • Google
  • Microsoft Azure AD
  • Okta
  • Keycloak
  • Auth0
  • Any OIDC-compliant provider

Configuration

  • Name - Provider display name
  • Issuer URL - OIDC discovery endpoint
  • Client ID - OAuth client ID
  • Client secret - OAuth client secret
  • Scopes - OAuth scopes (default: openid profile email)
OIDC Setup guide

See the OIDC Configuration Guide for detailed setup instructions with Keycloak and other providers.

LDAP/Active Directory Enterprise

Connect to LDAP or Active Directory for user authentication.

Enterprise feature

LDAP/Active Directory integration requires an Enterprise license.

Connection settings

  • Server URL - LDAP server (e.g., ldap://ldap.example.com:389)
  • Bind DN - Service account DN for searching
  • Bind password - Service account password
  • Base DN - Search base (e.g., dc=example,dc=com)

User search

  • User filter - LDAP filter template
    • OpenLDAP: (uid={{username}})
    • Active Directory: (sAMAccountName={{username}})
  • Username attribute - Attribute for username (uid, sAMAccountName)
  • Email attribute - Attribute for email (mail)
  • Display name attribute - Attribute for display name (cn)

Group settings

  • Group base DN - Where to search for groups
  • Admin group - Group DN for admin access
  • Member filter - Filter to find user's groups

TLS settings

  • Enable TLS - Use LDAPS or StartTLS
  • CA certificate - Custom CA for verification
LDAP Setup guide

See the LDAP/AD Configuration Guide for detailed setup instructions.

Roles (RBAC) Enterprise

Configure role-based access control for granular permissions.

System roles

  • Admin - Full access to everything
  • Operator - Manage containers, images, stacks
  • Viewer - Read-only access

Custom roles

Create roles with granular permissions:

  • Containers - view, create, edit, start/stop, remove, exec, logs
  • Images - view, pull, remove
  • Volumes - view, create, remove, browse
  • Networks - view, create, remove
  • Stacks - view, create, edit, deploy, remove
  • And more...

Environment scoping

Custom roles can be scoped to specific environments:

  • All environments - Role applies everywhere
  • Specific environments - Role only applies to selected environments

License

Activate and manage your Enterprise license.

Enterprise features

An Enterprise license unlocks:

  • Role-based access control (RBAC)
  • LDAP/Active Directory integration
  • Audit logging
  • Priority support

Activation

  1. Enter your license name (customer name)
  2. Enter your license key
  3. Click Activate

The license is validated against:

  • Customer name
  • Hostname (or wildcard)
  • Expiration date
  • Cryptographic signature

Enterprise features

Enterprise edition adds advanced security and compliance features for organizations.

Role-based access control

RBAC provides fine-grained control over who can access what:

  • Users can be assigned multiple roles
  • Roles define permissions for resources and actions
  • Environment scoping limits role access to specific environments

Free vs Enterprise

Feature Free Edition Enterprise
Authentication Yes (SSO + local users) Yes
Permissions All users have full access Granular RBAC
Environment scoping No Yes

Audit logging

Track all user actions for compliance and security auditing.

Audit logs capture:

  • Who performed the action (user)
  • What action was performed (create, update, delete, start, stop, etc.)
  • What resource was affected (container, image, stack, etc.)
  • When the action occurred (timestamp)
  • Additional context (IP address, user agent)

Multi-factor authentication

Add an extra layer of security with TOTP-based MFA. This feature is available in both free and enterprise edition.

Setup process

  1. Go to your Profile page
  2. Click Enable MFA
  3. Scan the QR code with an authenticator app (Google Authenticator, Authy, etc.)
  4. Enter the verification code
  5. Save your backup codes securely
Backup codes

Store your backup codes in a safe place. You can use them to access your account if you lose your authenticator device.

Keyboard shortcuts

Global

Shortcut Action
Esc Close modal / Clear search
+ K / Ctrl + K Open command palette - quick navigation and actions

Terminal

Shortcut Action
Cmd + L Clear terminal
Cmd + C Copy selection
Cmd + V Paste

Troubleshooting

Dockhand won't start

  • Check Docker socket is accessible: docker ps
  • Verify port 5173 is not in use
  • Check container logs: docker logs dockhand

Can't connect to environment

  • Verify Docker is running on the target host
  • Check firewall rules allow connection
  • For Hawser: verify agent is running and token is correct

Locked out of authentication

Use emergency scripts to regain access:

Emergency scripts

Recovery scripts are located in /app/scripts/emergency/ inside the container:

Bash
# Disable authentication
docker exec -it dockhand /app/scripts/emergency/disable-auth.sh

# Create admin user (admin/admin123)
docker exec -it dockhand /app/scripts/emergency/create-admin.sh

# Reset a user's password
docker exec -it dockhand /app/scripts/emergency/reset-password.sh username NewPassword123

# List all users
docker exec -it dockhand /app/scripts/emergency/list-users.sh

# Clear all sessions (force re-login)
docker exec -it dockhand /app/scripts/emergency/clear-sessions.sh

# Backup database
docker exec -it dockhand /app/scripts/emergency/backup-db.sh /app/data/backups
Security note

Emergency scripts require shell access to the container. In production, restrict access to the Docker socket and container.

API reference

Dockhand exposes a REST API that can be used for automation and integration with other tools. All endpoints are available at /api/.

Authentication

When authentication is enabled, API requests must include a valid session cookie. Use the same authentication as the web UI.

Containers

Method Endpoint Description
GET /api/containers List all containers
POST /api/containers Create a new container
GET /api/containers/[id] Get container details
DELETE /api/containers/[id] Remove container
POST /api/containers/[id]/start Start container
POST /api/containers/[id]/stop Stop container
POST /api/containers/[id]/restart Restart container
GET /api/containers/[id]/logs Get container logs

Stacks

Method Endpoint Description
GET /api/stacks List all compose stacks
POST /api/stacks Create a new stack
POST /api/stacks/[name]/start Start stack
POST /api/stacks/[name]/stop Stop stack
DELETE /api/stacks/[name] Remove stack

Images

Method Endpoint Description
GET /api/images List all images
POST /api/images/pull Pull an image from registry
DELETE /api/images/[id] Remove image
POST /api/images/scan Scan image for vulnerabilities

Volumes & Networks

Method Endpoint Description
GET /api/volumes List all volumes
POST /api/volumes Create a volume
DELETE /api/volumes/[name] Remove volume
GET /api/networks List all networks
POST /api/networks Create a network
DELETE /api/networks/[id] Remove network

Other endpoints

Method Endpoint Description
GET /api/activity Get activity log
GET /api/environments List environments
GET /api/dashboard/stats Get dashboard statistics
GET /api/schedules List scheduled tasks

Query parameters

Most endpoints accept an env query parameter to specify the target environment:

GET /api/containers?env=1
GET /api/images?env=2

Example: Using curl

Bash
# List containers
curl -s http://localhost:3000/api/containers | jq

# Restart a container
curl -X POST http://localhost:3000/api/containers/abc123/restart

# Pull an image
curl -X POST http://localhost:3000/api/images/pull \
  -H "Content-Type: application/json" \
  -d '{"image": "nginx:latest"}'

# Create a stack
curl -X POST http://localhost:3000/api/stacks \
  -H "Content-Type: application/json" \
  -d '{"name": "mystack", "compose": "version: \"3\"\\nservices:\\n  web:\\n    image: nginx"}'

Appendix: OIDC/SSO configuration guide

This guide explains how to configure OpenID Connect (OIDC) Single Sign-On in Dockhand.

Overview

Dockhand supports OIDC authentication, allowing users to log in using external identity providers:

  • Google
  • Microsoft Azure AD
  • Okta
  • Keycloak
  • Auth0
  • Any OIDC-compliant provider

Keycloak setup example

1. Create a realm

  1. Log in to Keycloak Admin Console
  2. Create a new realm (e.g., dockhand)

2. Create a client

  1. Go to Clients > Create client
  2. Configure:
    • Client ID: dockhand-app
    • Client type: OpenID Connect
    • Client authentication: ON (for confidential client)
  3. Click Next and configure:
    • Valid redirect URIs: https://your-domain/api/auth/oidc/callback
    • Web origins: https://your-domain
  4. Click Save
  5. Go to Credentials tab and copy the Client secret

3. Configure group mapper

To pass group membership to Dockhand for role mapping:

  1. Go to Clients > dockhand-app > Client scopes
  2. Click on dockhand-app-dedicated scope
  3. Click Add mapper > By configuration > Group Membership
  4. Configure:
    • Name: groups
    • Token Claim Name: groups
    • Full group path: OFF
    • Add to ID token: ON
    • Add to access token: ON
    • Add to userinfo: ON
  5. Click Save

4. Create groups

Create groups in Keycloak that map to Dockhand roles:

  1. Go to Groups > Create group
  2. Create groups such as:
    • dockhand-admins - for administrator access
    • dockhand-operators - for operator access
    • dockhand-viewers - for read-only access

5. Assign users to groups

  1. Go to Users > [select user] > Groups
  2. Click Join Group
  3. Select the appropriate group(s)

Dockhand configuration

1. Enable Enterprise license

Role mapping features require an Enterprise license:

  1. Go to Settings > License
  2. Enter your license name and key
  3. Click Activate

2. Configure OIDC provider

  1. Go to Settings > Auth > SSO
  2. Click Add provider
  3. Fill in the basic settings:
Field Example Value
Name Keycloak
Issuer URL https://keycloak.example.com/realms/dockhand
Client ID dockhand-app
Client secret (from Keycloak)
Redirect URI https://your-domain/api/auth/oidc/callback
Scopes openid profile email

3. Configure claim mappings (optional)

Field Default Description
Username claim preferred_username Claim for username
Email claim email Claim for email address
Display name claim name Claim for display name

4. Configure admin mapping

Grant admin access based on group membership:

  1. Edit the OIDC provider
  2. Scroll to Groups/roles claim section
  3. Configure:
    • Claim name: groups
    • Admin value(s): dockhand-admins

Users with dockhand-admins in their groups claim will automatically receive Admin role.

5. Configure role mappings (Enterprise)

Map additional groups to Dockhand roles:

  1. Edit the OIDC provider
  2. Scroll to Claim to role mappings section
  3. Click Add mapping
  4. For each mapping, configure:
    • Claim name: groups
    • Claim value: e.g., dockhand-operators
    • Role: Select from dropdown
Keycloak Group Dockhand Role
dockhand-admins Admin (via admin mapping)
dockhand-operators Operator
dockhand-viewers Viewer

Other identity providers

Google

Configuration
Issuer URL: https://accounts.google.com
Scopes: openid profile email

Note: Google doesn't support custom claims for role mapping. All Google users will need manual role assignment.

Azure AD

Configuration
Issuer URL: https://login.microsoftonline.com/{tenant-id}/v2.0
Scopes: openid profile email

For role mapping, configure Azure AD to include group claims in the token.

Okta

Configuration
Issuer URL: https://{your-domain}.okta.com
Scopes: openid profile email groups

Configure a groups claim in the Authorization Server.

Troubleshooting OIDC

User has no permissions after login

  • Verify the user is assigned to groups in your IdP
  • Check that the groups mapper is configured correctly
  • Ensure Add to ID token is enabled for the groups mapper
  • Verify the claim name matches in Dockhand config (case-sensitive)

Admin mapping not working

  • Verify the admin claim name matches exactly (case-sensitive)
  • Check that the admin value matches the group name exactly
  • Ensure the user is a member of the admin group in your IdP

Redirect URI mismatch error

  • Ensure the redirect URI in Dockhand matches exactly what's configured in your IdP
  • Check for trailing slashes
  • Verify the protocol (http vs https) matches

Token claims not appearing

For Keycloak:

  1. Go to Clients > [client] > Client scopes
  2. Verify mappers are configured
  3. Use Keycloak's Evaluate feature to test token contents:
    • Go to Clients > [client] > Client scopes > Evaluate
    • Select a user and click Generated ID token
    • Verify the groups claim is present
Security considerations
  • Use HTTPS in production - Never use HTTP for OIDC in production environments
  • Protect client secrets - Store client secrets securely, never commit to version control
  • Validate redirect URIs - Only allow specific, known redirect URIs
  • Use short token lifetimes - Configure appropriate token expiration in your IdP
  • Regular audits - Review OIDC user access and role mappings periodically

Appendix: LDAP/Active Directory configuration guide

This guide explains how to configure LDAP or Active Directory authentication in Dockhand.

Enterprise feature

LDAP/Active Directory integration requires an Enterprise license.

Supported directories

  • OpenLDAP
  • Microsoft Active Directory
  • FreeIPA
  • 389 Directory Server
  • Any LDAP v3 compliant directory

How LDAP authentication works

  1. User enters username and password in Dockhand
  2. Dockhand connects to LDAP server using bind credentials (service account)
  3. Searches for the user entry using the configured filter
  4. Attempts to bind as the found user with the provided password
  5. If successful, retrieves user attributes (email, display name)
  6. Optionally checks group membership for admin/role assignment
  7. Creates or updates user in Dockhand and establishes session

Key terminology

Term Description
DN (Distinguished Name) Unique identifier for an entry, e.g., cn=john,ou=users,dc=example,dc=com
Base DN Starting point for searches, e.g., dc=example,dc=com
Bind DN Service account DN used to search the directory
Filter LDAP query to find entries, e.g., (uid=john)
Attribute Property of an entry, e.g., mail, cn, uid

OpenLDAP configuration

Example directory structure

LDAP Tree
dc=example,dc=com
├── ou=users
│   ├── uid=john (cn=John Doe, mail=john@example.com)
│   └── uid=jane (cn=Jane Smith, mail=jane@example.com)
└── ou=groups
    ├── cn=dockhand-admins (member: uid=john,ou=users,dc=example,dc=com)
    └── cn=dockhand-users (member: uid=jane,ou=users,dc=example,dc=com)

Dockhand configuration for OpenLDAP

Field Value
Name Corporate OpenLDAP
Server URL ldap://ldap.example.com:389
Bind DN cn=readonly,dc=example,dc=com
Bind Password (service account password)
Base DN ou=users,dc=example,dc=com
User filter (uid={{username}})
Username attribute uid
Email attribute mail
Display name attribute cn
Group base DN ou=groups,dc=example,dc=com
Admin group cn=dockhand-admins,ou=groups,dc=example,dc=com

Active Directory configuration

Example AD structure

AD Tree
DC=corp,DC=example,DC=com
├── OU=Users
│   ├── CN=John Doe (sAMAccountName=jdoe, mail=jdoe@example.com)
│   └── CN=Jane Smith (sAMAccountName=jsmith, mail=jsmith@example.com)
└── OU=Groups
    ├── CN=Dockhand Admins
    └── CN=Dockhand Users

Dockhand configuration for Active Directory

Field Value
Name Corporate AD
Server URL ldap://dc01.corp.example.com:389
Bind DN CN=Service Account,OU=Service Accounts,DC=corp,DC=example,DC=com
Base DN OU=Users,DC=corp,DC=example,DC=com
User filter (sAMAccountName={{username}})
Username attribute sAMAccountName
Email attribute mail
Display name attribute displayName
Group base DN OU=Groups,DC=corp,DC=example,DC=com
Admin group CN=Dockhand Admins,OU=Groups,DC=corp,DC=example,DC=com

Alternative AD user filters

User Filter Examples
# By sAMAccountName (most common)
(sAMAccountName={{username}})

# By userPrincipalName (email-style login)
(userPrincipalName={{username}})

# By both (allow either format)
(|(sAMAccountName={{username}})(userPrincipalName={{username}}))

# Only enabled accounts
(&(sAMAccountName={{username}})(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

Group membership filters

Member Filter Examples
# OpenLDAP with groupOfNames
(&(objectClass=groupOfNames)(member={{user_dn}}))

# OpenLDAP with posixGroup
(&(objectClass=posixGroup)(memberUid={{username}}))

# Active Directory
(&(objectClass=group)(member={{user_dn}}))

The {{user_dn}} placeholder is replaced with the user's full DN.

Role mappings (Enterprise)

Map LDAP groups to Dockhand roles:

  1. Click Add mapping
  2. Enter the full group DN
  3. Select the Dockhand role
LDAP Group DN Dockhand Role
cn=dockhand-admins,ou=groups,dc=example,dc=com Admin (via admin group)
cn=dockhand-operators,ou=groups,dc=example,dc=com Operator
cn=dockhand-viewers,ou=groups,dc=example,dc=com Viewer

TLS/SSL configuration

Server URL formats:

  • ldap://hostname:389 - Plain LDAP (port 389)
  • ldaps://hostname:636 - LDAP over SSL (port 636)
  • ldap://hostname:389 with TLS enabled - StartTLS

For self-signed certificates, add the CA certificate in TLS settings.

Troubleshooting LDAP

Connection refused

  • Verify LDAP server is running and accessible
  • Check firewall rules (ports 389/636)
  • Test connectivity: telnet ldap.example.com 389

Invalid credentials (Bind DN)

  • Verify Bind DN is correct and complete
  • Check password is correct
  • Ensure service account is not locked/disabled

User not found

  • Verify Base DN includes the user's location
  • Test user filter manually with ldapsearch:
Bash
# OpenLDAP
ldapsearch -x -H ldap://localhost:389 \
  -D "cn=admin,dc=example,dc=com" \
  -W \
  -b "ou=users,dc=example,dc=com" \
  "(uid=john)"

# Active Directory
ldapsearch -x -H ldap://dc01.corp.example.com:389 \
  -D "CN=Service Account,DC=corp,DC=example,DC=com" \
  -W \
  -b "DC=corp,DC=example,DC=com" \
  "(sAMAccountName=jdoe)"

User logs in but has no permissions

  • Verify user is member of appropriate LDAP group
  • Check group DN matches exactly (case-sensitive)
  • Verify member filter is correct for your directory type
  • Ensure role mappings are configured

TLS/SSL certificate errors

  • For self-signed certificates, add the CA certificate in TLS settings
  • Verify server hostname matches certificate CN/SAN
  • Check certificate is not expired
Security considerations
  • Use TLS in production - Never send credentials over plain LDAP in production
  • Principle of least privilege - Bind account should only have read access
  • Protect bind credentials - Store bind password securely
  • Audit group membership - Regularly review who has admin access
  • Monitor failed logins - Watch for brute force attempts