Skip to content

Finsys/hawser

Repository files navigation

Hawser

Hawser Logo

GitHub Release Build Release Go Version Docker Image License

Remote Docker agent for Dockhand - manage Docker hosts anywhere.

Overview

Hawser is a lightweight Go agent that enables Dockhand to manage Docker hosts in various network configurations. It supports two operational modes:

  • Standard Mode: Agent listens for incoming connections (ideal for LAN/homelab with static IPs)
  • Edge Mode: Agent initiates outbound WebSocket connection to Dockhand (ideal for VPS, NAT, dynamic IP)

Quick Start

Binary

Download the latest release from GitHub Releases.

Standard Mode:

hawser --port 2376

Standard Mode with Token Authentication (optional):

TOKEN=your-secret-token hawser --port 2376

Standard Mode with TLS (optional):

TLS_CERT=/path/to/server.crt TLS_KEY=/path/to/server.key hawser --port 2376

Standard Mode with TLS and Token (recommended for production):

TLS_CERT=/path/to/server.crt TLS_KEY=/path/to/server.key TOKEN=your-secret-token hawser --port 2376

Edge Mode:

hawser --server wss://your-dockhand.example.com/api/hawser/connect --token your-token

Edge Mode with Self-Signed Certificate:

CA_CERT=/path/to/dockhand-ca.crt hawser --server wss://your-dockhand.example.com/api/hawser/connect --token your-token

Edge Mode with TLS Skip Verify (insecure, for testing):

TLS_SKIP_VERIFY=true hawser --server wss://your-dockhand.example.com/api/hawser/connect --token your-token

Systemd Service

Quick Install

  1. Download and install the binary:
curl -fsSL https://raw.githubusercontent.com/Finsys/hawser/main/scripts/install.sh | bash
  1. Configure the service:
sudo nano /etc/hawser/config

Example config for Standard Mode:

# Standard mode - listen for connections
PORT=2376
# Optional: require token authentication
TOKEN=your-secret-token

Example config for Edge Mode:

# Edge mode - connect to Dockhand server
DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect
TOKEN=your-agent-token
  1. Start the service:
sudo systemctl enable --now hawser

Full Systemd Service File

If you prefer to set up the systemd service manually, here's the complete service file:

/etc/systemd/system/hawser.service

[Unit]
Description=Hawser - Remote Docker Agent for Dockhand
Documentation=https://github.com/Finsys/hawser
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

# Security hardening
NoNewPrivileges=false
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/run/docker.sock /data/stacks

[Install]
WantedBy=multi-user.target

/etc/hawser/config (Standard Mode example):

# Hawser Configuration
# See https://github.com/Finsys/hawser for documentation

# Standard Mode
PORT=2376

# Docker socket path
DOCKER_SOCKET=/var/run/docker.sock

# Agent identification (optional)
# AGENT_NAME=my-server

# Token authentication (optional)
# TOKEN=your-secret-token

# TLS configuration (optional)
# TLS_CERT=/etc/hawser/server.crt
# TLS_KEY=/etc/hawser/server.key

/etc/hawser/config (Edge Mode example):

# Hawser Configuration
# See https://github.com/Finsys/hawser for documentation

# Edge Mode - connect to Dockhand server
DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect
TOKEN=your-agent-token

# Docker socket path
DOCKER_SOCKET=/var/run/docker.sock

# Agent identification (optional)
# AGENT_NAME=my-server

# TLS configuration for self-signed Dockhand (optional)
# CA_CERT=/etc/hawser/dockhand-ca.crt
# TLS_SKIP_VERIFY=false

# Connection settings (optional)
# HEARTBEAT_INTERVAL=30
# RECONNECT_DELAY=1
# MAX_RECONNECT_DELAY=60

Manual installation steps:

# 1. Download binary
curl -fsSL https://github.com/Finsys/hawser/releases/latest/download/hawser_linux_amd64.tar.gz | tar xz
sudo install -m 755 hawser /usr/local/bin/hawser

# 2. Create config directory
sudo mkdir -p /etc/hawser

# 3. Create config file (edit with your settings)
sudo tee /etc/hawser/config << 'EOF'
PORT=2376
DOCKER_SOCKET=/var/run/docker.sock
EOF

# 4. Create systemd service file
sudo tee /etc/systemd/system/hawser.service << 'EOF'
[Unit]
Description=Hawser - Remote Docker Agent for Dockhand
Documentation=https://github.com/Finsys/hawser
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

NoNewPrivileges=false
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/run/docker.sock /data/stacks

[Install]
WantedBy=multi-user.target
EOF

# 5. Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable --now hawser

# 6. Check status
sudo systemctl status hawser
sudo journalctl -u hawser -f

Docker

Note: Hawser stores compose stack files in /data/stacks. This is declared as a VOLUME in the image, so it's always writable. For persistent stack files, mount a host directory to this path.

Standard Mode - Agent listens for connections:

docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -p 2376:2376 \
  ghcr.io/finsys/hawser:latest

Standard Mode with Token Authentication (optional):

docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -p 2376:2376 \
  -e TOKEN=your-secret-token \
  ghcr.io/finsys/hawser:latest

Standard Mode with TLS (optional):

docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -v /path/to/certs:/certs:ro \
  -p 2376:2376 \
  -e TLS_CERT=/certs/server.crt \
  -e TLS_KEY=/certs/server.key \
  ghcr.io/finsys/hawser:latest

Standard Mode with TLS and Token (recommended for production):

docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -v /path/to/certs:/certs:ro \
  -p 2376:2376 \
  -e TLS_CERT=/certs/server.crt \
  -e TLS_KEY=/certs/server.key \
  -e TOKEN=your-secret-token \
  ghcr.io/finsys/hawser:latest

Edge Mode - Agent connects to Dockhand:

docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -e DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect \
  -e TOKEN=your-agent-token \
  ghcr.io/finsys/hawser:latest

Edge Mode with Self-Signed Certificate:

docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -v /path/to/dockhand-ca.crt:/certs/ca.crt:ro \
  -e DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect \
  -e TOKEN=your-agent-token \
  -e CA_CERT=/certs/ca.crt \
  ghcr.io/finsys/hawser:latest

Building Docker image locally

For local development or custom builds, use the multi-stage Dockerfile.dev which builds from source:

# Clone repository
git clone https://github.com/Finsys/hawser.git
cd hawser

# Build from source (recommended for local development)
docker build -f Dockerfile.dev -t hawser:local .

# Run locally built image - Standard mode
docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -p 2376:2376 \
  hawser:local

# Run locally built image - Edge mode
docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v hawser_stacks:/data/stacks \
  -e DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect \
  -e TOKEN=your-agent-token \
  hawser:local

Note: The default Dockerfile is used by GoReleaser for release builds and expects a pre-built binary. Use Dockerfile.dev for building from source.

Multi-architecture builds

The official images on ghcr.io/finsys/hawser are multi-arch (amd64 + arm64). For local multi-arch builds:

# Create a builder (first time only)
docker buildx create --name mybuilder --use

# Build for multiple platforms
docker buildx build -f Dockerfile.dev \
  --platform linux/amd64,linux/arm64 \
  -t hawser:local \
  --load .

Docker health check

The Hawser Docker image includes a built-in health check that verifies Docker connectivity. This works in both Standard and Edge modes.

How it works:

  • The container runs wget against the /_hawser/health endpoint every 30 seconds
  • Both modes expose a minimal HTTP server on the configured port (default: 2376) for health checks
  • The health check verifies that Hawser can communicate with the Docker daemon

Health check response:

# Standard mode
curl http://localhost:2376/_hawser/health
{"status":"healthy"}

# Edge mode (includes connection status)
curl http://localhost:2376/_hawser/health
{"status":"healthy","mode":"edge","connected":true}

Container status:

# Check container health status
docker inspect --format='{{.State.Health.Status}}' hawser
# healthy

# View health check logs
docker inspect --format='{{json .State.Health}}' hawser | jq

Custom health check (optional):

If you need custom health check settings, you can override the built-in health check:

docker run -d \
  --name hawser \
  -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 \
  --health-cmd="wget -q --spider http://localhost:2376/_hawser/health || exit 1" \
  --health-interval=30s \
  --health-timeout=5s \
  --health-retries=3 \
  --health-start-period=10s \
  ghcr.io/finsys/hawser:latest

Configuration

Hawser is configured via environment variables:

Variable Description Default
DOCKHAND_SERVER_URL WebSocket URL for Edge mode -
TOKEN Authentication token -
CA_CERT Path to CA certificate for Edge mode (self-signed Dockhand) -
TLS_SKIP_VERIFY Skip TLS verification for Edge mode (insecure) false
PORT HTTP server port (Standard mode) 2376
TLS_CERT Path to TLS certificate (Standard mode server cert) -
TLS_KEY Path to TLS private key (Standard mode server key) -
DOCKER_SOCKET Docker socket path /var/run/docker.sock
STACKS_DIR Directory for compose stack files (requires Dockhand 1.0.5+) /tmp/stacks
AGENT_ID Unique agent identifier Auto-generated UUID
AGENT_NAME Human-readable agent name Hostname
HEARTBEAT_INTERVAL Heartbeat interval in seconds 30
REQUEST_TIMEOUT Request timeout in seconds 30
RECONNECT_DELAY Initial reconnect delay (Edge mode) 1
MAX_RECONNECT_DELAY Maximum reconnect delay 60
LOG_LEVEL Logging level: debug, info, warn, error info

Mode Detection

Hawser automatically detects the operational mode:

  • If DOCKHAND_SERVER_URL and TOKEN are set → Edge Mode
  • Otherwise → Standard Mode

Log Levels

The LOG_LEVEL environment variable controls verbosity:

Level Description
debug All messages including Docker API calls (method, path, status codes)
info Standard operational messages (connections, startup, shutdown)
warn Warnings only
error Errors only

Example: Debug mode

# Binary
LOG_LEVEL=debug hawser --port 2376

# Docker
docker run -d \
  --name hawser \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -p 2376:2376 \
  -e LOG_LEVEL=debug \
  ghcr.io/finsys/hawser:latest

Debug mode logs all Docker API requests, which is useful for troubleshooting connectivity issues.

Features

Docker API Proxy

Hawser provides full access to the Docker API:

  • Container management (create, start, stop, remove)
  • Image operations (pull, list, remove)
  • Volume and network management
  • Log streaming
  • Interactive exec sessions

Docker Compose Support

Hawser includes Docker Compose support for stack operations:

  • up - Deploy stack
  • down - Remove stack
  • pull - Pull images
  • ps - List services
  • logs - View logs

Host Metrics

Hawser collects and reports host metrics:

  • CPU usage (per-core and total)
  • Memory (total, used, available)
  • Disk usage (Docker data directory)
  • Network I/O statistics

Metrics are sent every 30 seconds in Edge mode.

Reliability

  • Auto-reconnect: Edge mode automatically reconnects with exponential backoff
  • Heartbeat: Regular keepalive messages maintain connection health
  • Graceful shutdown: Clean shutdown on SIGTERM/SIGINT

Docker API Version Compatibility

Hawser automatically negotiates the Docker API version with the daemon. When running Docker Compose operations, Hawser sets the DOCKER_API_VERSION environment variable to match the daemon's reported API version. This ensures compatibility when the Docker CLI version differs from the daemon version - for example, when using an older Docker CLI with a newer Docker daemon that requires a higher minimum API version.

API Endpoints

Standard Mode

In Standard mode, Hawser proxies all Docker API endpoints plus:

Endpoint Description
/_hawser/health Health check (no auth required)
/_hawser/info Agent information

Health Check

# Standard mode
curl http://localhost:2376/_hawser/health
# {"status":"healthy"}

# Edge mode (includes WebSocket connection status)
curl http://localhost:2376/_hawser/health
# {"status":"healthy","mode":"edge","connected":true}

Security Considerations

  1. Docker Socket Access: Hawser requires access to the Docker socket, which provides full control over Docker. Run with appropriate access controls.

  2. Network Security:

    • Standard mode: Use TLS and/or token authentication
    • Edge mode: Use WSS (TLS-encrypted WebSocket)
  3. Token Security: Tokens should be strong, randomly generated strings. In Dockhand, tokens are shown only once when generated.

Building from Source

# Clone repository
git clone https://github.com/Finsys/hawser.git
cd hawser

# Build
go build -o hawser ./cmd/hawser

# Run
./hawser --port 2376

Docker Build

docker build -t hawser .

Contributing

Contributions are welcome! Please read the contributing guidelines before submitting a pull request.

License

MIT License - see LICENSE for details.

Related


Made with ❤️ and mass amounts of ☕ by Finsys for Dockhand

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages