Files
Docker-Compose/Docker_GUI_Managers/dockhand

Source: https://dockhand.pro/

Deploy

Must have Docker installed: https://wiki.gabesville.com/books/docker/page/install-docker

Run the docker command to install and run Dockhand: sudo docker run -d -p 3000:3000 --name dockhand --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /srv/docker/dockhand/dockhand_data:/app/data fnsys/dockhand:latest

Go to http://IPADDRESS:3000 to access

If firewall(UFW) is enabled you may need to allow port 3000 (test first before creating the rule)

Updating

  1. CD to location you want the update script created
  2. sudo nano update-dockhand.sh
  3. Copypasta into file:
sudo docker stop dockhand
sleep 10s
sudo docker rm dockhand
sudo docker image rm -f fnsys/dockhand:latest
sleep 10s
sudo docker run -d -p 3000:3000 --name dockhand --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /srv/docker/dockhand/dockhand_data:/app/data fnsys/dockhand:latest
  1. sudo chmod u+x update-dockhand.sh
  2. to run: bash update-dockhand.sh

How variables and secrets are handled:

This document summarizes how environment variables and secrets behave when using Dockerhand to deploy a stack from a compose.yaml and .env file.


Mental Model

Dockerhand has two different injection mechanisms:

Type When injected Usable in ${VAR} Available in container
Variables Before docker compose Yes Yes
Secrets At container runtime No Yes

Key takeaway:

Dockerhand secrets do not participate in Docker Compose variable interpolation.


.env File Usage

Use .env for:

  • Non-secret defaults
  • Local development
  • Structural configuration

Example:

DB_USERNAME=postgres
DB_HOSTNAME=database
DB_PORT=5432
DB_DATABASE_NAME=immich
IMMICH_VERSION=release
UPLOAD_LOCATION=/mnt/media


⚠️ Do not rely on .env for secrets in production.

❌ What Does NOT Work (Common Pitfall)

This fails when DB_PASSWORD is marked as a secret in Dockerhand:

environment:
  DB_PASSWORD: ${DB_PASSWORD}


Reason:

Secrets are injected after Compose parsing

${DB_PASSWORD} resolves to empty

✅ Correct Pattern for Dockerhand Secrets
Rule

Never interpolate secrets with ${VAR}.
Declare the variable name only.

compose.yaml (Canonical Pattern)
Application container (e.g. Immich)
services:
  immich-server:
    env_file:
      - .env
    environment:
      DB_USERNAME:
      DB_PASSWORD:
      DB_HOSTNAME:
      DB_PORT:
      DB_DATABASE_NAME:

Database container (Postgres)
services:
  database:
    environment:
      POSTGRES_USER:
      POSTGRES_PASSWORD:

Dockerhand Configuration
Variables (non-secret)
DB_USERNAME=postgres
POSTGRES_USER=postgres

Secrets
DB_PASSWORD=********
POSTGRES_PASSWORD=********


✔ Secrets are injected by name
✔ Containers receive them at runtime
✔ No ${VAR} expansion involved

Why This Works

Compose does not attempt interpolation

Dockerhand injects secrets directly into container environments

Applications read expected variables normally

No accidental empty passwords

No secret leakage via docker inspect

Postgres-Specific Notes

POSTGRES_PASSWORD is only used on initial DB creation

Existing volumes require password changes via:

ALTER USER postgres WITH PASSWORD 'newpassword';


Authentication failures can be misleading when the app receives an empty password

Debugging Checklist

If authentication fails:

Confirm secret is not interpolated (${VAR})

Confirm variable name matches what the app expects

Check inside container:

env | grep PASSWORD


Check Postgres logs for auth method (scram-sha-256)

TL;DR

.env = defaults & structure

Dockerhand variables = safe overrides

Dockerhand secrets = runtime injection only

Never use ${VAR} for secrets

Declare env var names and let Dockerhand fill them

Final Rule to Remember

If its marked as a secret in Dockerhand,
Compose must never try to expand it.