diff --git a/blueprints/wud/docker-compose.yml b/blueprints/wud/docker-compose.yml new file mode 100644 index 00000000..5b0d437f --- /dev/null +++ b/blueprints/wud/docker-compose.yml @@ -0,0 +1,85 @@ +services: + wud: + image: ghcr.io/getwud/wud:9.5.0 + restart: unless-stopped + env_file: + - path: .env + required: false + environment: + WUD_AUTH_ADMIN_USER: "${WUD_AUTH_ADMIN_USER:-admin}" + WUD_AUTH_ADMIN_PASSWORD: "${WUD_AUTH_ADMIN_PASSWORD:?Keep the generated administrator password}" + WUD_SERVER_PORT: "3000" + WUD_SERVER_TLS_ENABLED: "false" + WUD_STORE_PATH: /store + WUD_STORE_FILE: wud.sqlite + WUD_WATCHER_DOCKER_LOCAL_HOST: wud-socket-proxy + WUD_WATCHER_DOCKER_LOCAL_PORT: "2375" + WUD_WATCHER_DOCKER_LOCAL_WATCHBYDEFAULT: "${WUD_WATCHER_DOCKER_LOCAL_WATCHBYDEFAULT:-true}" + WUD_WATCHER_DOCKER_LOCAL_WATCHALL: "${WUD_WATCHER_DOCKER_LOCAL_WATCHALL:-false}" + WUD_WATCHER_DOCKER_LOCAL_WATCHATSTART: "true" + WUD_WATCHER_DOCKER_LOCAL_CRON: "${WUD_WATCHER_DOCKER_LOCAL_CRON:-0 * * * *}" + WUD_LOG_LEVEL: "${WUD_LOG_LEVEL:-info}" + WUD_LOG_FORMAT: json + TZ: "${TZ:-UTC}" + expose: + - "3000" + volumes: + - wud-data:/store + depends_on: + wud-socket-proxy: + condition: service_healthy + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + healthcheck: + test: ["CMD", "curl", "--fail", "--silent", "http://127.0.0.1:3000/health"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s + stop_grace_period: 30s + logging: &logging + driver: json-file + options: + max-size: "10m" + max-file: "3" + + wud-socket-proxy: + image: ghcr.io/tecnativa/docker-socket-proxy:v0.5.0 + restart: unless-stopped + environment: + CONTAINERS: "1" + IMAGES: "1" + EVENTS: "1" + PING: "1" + VERSION: "1" + POST: "0" + expose: + - "2375" + volumes: + - type: bind + source: /var/run/docker.sock + target: /var/run/docker.sock + read_only: true + bind: + create_host_path: false + read_only: true + tmpfs: + - /run + - /tmp + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + healthcheck: + test: ["CMD", "wget", "--quiet", "--output-document=-", "http://127.0.0.1:2375/_ping"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + stop_grace_period: 30s + logging: *logging + +volumes: + wud-data: diff --git a/blueprints/wud/environment.md b/blueprints/wud/environment.md new file mode 100644 index 00000000..4077464e --- /dev/null +++ b/blueprints/wud/environment.md @@ -0,0 +1,67 @@ +# Environment variables + +This template targets WUD **9.5.0**. Provider settings are read from the environment at startup; add optional values in Dokploy's Environment tab and redeploy. The optional `.env` file forwards additional WUD settings without requiring a Compose edit. Values explicitly set in Compose take precedence over `.env`. + +## Required administrator settings + +| Variable | Template value | Purpose | +| --- | --- | --- | +| `WUD_AUTH_ADMIN_USER` | `admin` | Local administrator username; editable. | +| `WUD_AUTH_ADMIN_PASSWORD` | Generated random hexadecimal string | Required by this template. Plaintext bootstrap input; WUD stores a bcrypt hash. Reapplied to this account on **every startup**. Rotate it here rather than only in the UI. | + +No provider credential or separate session secret is required. Upstream also supports `WUD_AUTH_ADMIN_HASH`, legacy `WUD_AUTH_BASIC_*`, and OIDC; those are alternative authentication designs, not additional installation requirements. Do not set a conflicting admin hash alongside this template's password. See [authentication](https://getwud.app/docs/configuration/authentications/). + +## Editable defaults + +| Variable | Template value | Purpose | +| --- | --- | --- | +| `WUD_WATCHER_DOCKER_LOCAL_WATCHBYDEFAULT` | `true` | Monitor running containers that pass the filters. Set `false` for explicit opt-in labels. | +| `WUD_WATCHER_DOCKER_LOCAL_EXCLUDE` | `^dokploy([._-]\|$)` | Skip standard Dokploy infrastructure names by default. Remove this variable and redeploy to include them. Explicit `wud.watch=true` labels override the filter. See [monitoring scope](instructions.md#dokploy-infrastructure-is-ignored-by-default). | +| `WUD_WATCHER_DOCKER_LOCAL_WATCHALL` | `false` | Set `true` to include stopped containers. | +| `WUD_WATCHER_DOCKER_LOCAL_CRON` | `0 * * * *` | Hourly scan in `TZ`; upstream adds up to 60 seconds of random jitter. | +| `WUD_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error`, or `fatal`. | +| `TZ` | `UTC` | Time zone for cron and timestamps, for example `Europe/Paris`. | + +The exclusion matches container names, not image names: application Redis/PostgreSQL containers with other names remain monitored. To include Dokploy infrastructure, remove the entire exclusion line, save and redeploy, then select **Containers → Watch now**. Do not leave an empty `WUD_WATCHER_DOCKER_LOCAL_EXCLUDE=` entry: WUD rejects empty filter values. No Compose edit is needed. + +## Fixed service settings + +These values are set in Compose. Change them there only as part of a coordinated customization. + +| Variable | Value | Reason | +| --- | --- | --- | +| `WUD_WATCHER_DOCKER_LOCAL_HOST` | `wud-socket-proxy` | Keeps the Docker socket out of the WUD container. | +| `WUD_WATCHER_DOCKER_LOCAL_PORT` | `2375` | Private proxy port, never published. | +| `WUD_WATCHER_DOCKER_LOCAL_WATCHATSTART` | `true` | Enables startup discovery when the stored container list is empty. For a populated store, use the watch action or scheduled scan. | +| `WUD_SERVER_PORT` | `3000` | Matches the Dokploy domain and health check. | +| `WUD_SERVER_TLS_ENABLED` | `false` | Traefik handles public HTTPS. | +| `WUD_STORE_PATH` | `/store` | Persistent volume target. | +| `WUD_STORE_FILE` | `wud.sqlite` | SQLite database filename. | +| `WUD_LOG_FORMAT` | `json` | Structured logs and direct Node process startup. | + +The socket proxy permits `CONTAINERS=1`, `IMAGES=1`, `EVENTS=1`, `PING=1`, and `VERSION=1`. `POST=0` blocks write methods; other API sections retain their denied defaults. These are fixed proxy service settings, not WUD environment variables. See [Docker Socket Proxy](https://github.com/Tecnativa/docker-socket-proxy). + +## Optional application and provider settings + +WUD's provider names are dynamic. For example, `LOCAL` identifies this template's Docker watcher and `ALERTS` can identify a notification trigger. The following are optional; use the linked official schemas for the fields of the providers you actually enable. + +| Variable or family | Default / use | Documentation | +| --- | --- | --- | +| `WUD_WATCHER_DOCKER_LOCAL_INCLUDE` | Unset; optional container-name or `label:` allowlist. The template's default exclusion is documented above. Explicit `wud.watch` labels take precedence over both filters. | [Docker watcher](https://getwud.app/docs/configuration/watchers/) | +| `WUD_WATCHER_DOCKER_LOCAL_WATCHEVENTS` | `true`; follows lifecycle events. | [Docker watcher](https://getwud.app/docs/configuration/watchers/) | +| `WUD_WATCHER_DOCKER_LOCAL_JITTER` | `60000` milliseconds; random scan delay. | [Docker watcher](https://getwud.app/docs/configuration/watchers/) | +| `WUD_REGISTRY_{TYPE}_{NAME}_*` | Optional private-registry credentials and registry-specific options. Public images can use anonymous access, subject to rate limits. | [Registries](https://getwud.app/docs/configuration/registries/) | +| `WUD_TRIGGER_{TYPE}_{NAME}_*` | Optional notification provider settings. Required credentials depend on the chosen provider. No triggers are configured by default. | [Triggers](https://getwud.app/docs/configuration/triggers/) | +| `WUD_AUTH_OIDC_{NAME}_*` | Optional SSO provider settings; issuer/client credentials and group mapping depend on the provider. | [OIDC](https://getwud.app/docs/configuration/authentications/oidc/) | +| `WUD_PUBLIC_URL` | Inferred from the request; set to your canonical HTTPS URL if needed for links or SSO. | [Authentication](https://getwud.app/docs/configuration/authentications/) | +| `WUD_SERVER_FEATURE_DELETE` | Upstream `true`; allows deleting a tracked record from WUD, not deleting its Docker container. | [Server](https://getwud.app/docs/configuration/server/) | +| `WUD_SERVER_CORS_ENABLED` | `false`; keep disabled for the normal same-origin dashboard. | [Server](https://getwud.app/docs/configuration/server/) | +| `WUD_SERVER_BASEPATH` | `/`; use a dedicated Dokploy domain with this template. | [Server](https://getwud.app/docs/configuration/server/) | +| `WUD_SERVER_ENABLED` | `true`; leave enabled for the dashboard and health check. | [Server](https://getwud.app/docs/configuration/server/) | +| `WUD_RUN_MODE` | `server`; leave unchanged. `oneshot` is a separate CLI deployment mode. | [Configuration](https://getwud.app/docs/configuration/) | +| `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` | Unset; optional outbound proxy. Include `wud-socket-proxy,localhost,127.0.0.1` in `NO_PROXY` when enabling a proxy. | [Proxy settings](https://getwud.app/docs/configuration/#proxy--tls-configuration) | +| `NODE_EXTRA_CA_CERTS` | Optional path to a mounted PEM CA bundle for private registries/proxies. | [Proxy settings](https://getwud.app/docs/configuration/#proxy--tls-configuration) | + +WUD supports `WUD_*__FILE` secret references. Mount a readable secret file and point the corresponding variable at its container path; adding a path alone does not create the file. The file value is read and trimmed at startup. This is an advanced alternative to storing a value directly in Dokploy's Environment tab. + +Per-container `wud.*` labels are not environment variables. Configure tag inclusion/exclusion and digest tracking on each monitored application; see the [labels guide](https://getwud.app/docs/configuration/watchers/labels/). In Compose, escape a literal dollar sign as `$$` where interpolation would otherwise occur. No `PUID`/`PGID` or database credentials are needed by the official WUD image. diff --git a/blueprints/wud/instructions.md b/blueprints/wud/instructions.md new file mode 100644 index 00000000..b726d57b --- /dev/null +++ b/blueprints/wud/instructions.md @@ -0,0 +1,72 @@ +# WUD (What's Up Docker?) + +WUD watches Docker containers, checks their image registries for newer versions, and displays available updates in a web dashboard. This template runs WUD 9.5.0 with persistent SQLite storage and a Docker socket proxy that permits monitoring requests and blocks Docker writes. Notifications are optional; automatic container updates are not configured. + +Official documentation: [Quick start](https://getwud.app/docs/quickstart/), [configuration](https://getwud.app/docs/configuration/), [Docker watcher](https://getwud.app/docs/configuration/watchers/), and [source code](https://github.com/getwud/wud). + +## Deploy in Dokploy + +1. Import the template. Dokploy generates `WUD_AUTH_ADMIN_PASSWORD`; the username defaults to `admin`. Keep the generated password private, or replace it with your own strong value. +2. Enable **Isolated Deployment** for this Compose service before deploying. Dokploy should place WUD and its socket proxy on the stack's private network. Do not add a domain or publish a port for `wud-socket-proxy`. +3. Set your domain to service `wud`, port `3000`, and enable HTTPS with HTTP redirection in Dokploy. Traefik terminates TLS; WUD uses HTTP inside the stack. +4. Deploy and wait for both services to become healthy. Open the domain and sign in using the values from the Environment tab. +5. Inspect the Containers page. The local watcher monitors running containers on the Docker host where this stack is deployed, excluding Dokploy infrastructure by default as described below. Registry checks run hourly, with up to 60 seconds of jitter. Use the UI's watch action when you need an immediate scan. + +No external database, registry account, notification service, or password-hashing command is required. Public registries work anonymously within their rate limits. Large hosts or frequent scans may need registry credentials. + +## Monitoring scope and Docker access + +### Dokploy infrastructure is ignored by default + +The template adds this editable filter to Dokploy's Environment tab: + +```dotenv +WUD_WATCHER_DOCKER_LOCAL_EXCLUDE=^dokploy([._-]|$) +``` + +It skips version tracking for containers named `dokploy` or beginning with `dokploy-`, `dokploy_`, or `dokploy.`. This covers standard Dokploy infrastructure names such as `dokploy-traefik`, `dokploy-postgres`, and `dokploy-redis`, including their usual Compose/Swarm suffixes. Dokploy upgrades remain managed through Dokploy. + +This is a **container-name** filter. Your application databases and other workloads with different names are still monitored; an application deliberately named with a matching `dokploy` prefix is also excluded. Customize the expression if your infrastructure uses different names. + +To track Dokploy infrastructure too, remove the entire `WUD_WATCHER_DOCKER_LOCAL_EXCLUDE` line from Dokploy's Environment tab, save, and redeploy. Do not leave an empty `WUD_WATCHER_DOCKER_LOCAL_EXCLUDE=` entry: WUD rejects empty filter values. Then select **Containers → Watch now** to run a fresh scan. To include just one excluded container, add `wud.watch: "true"` to that service's Docker labels and recreate it; this explicit label takes precedence over the exclusion filter. + +### Other monitoring controls + +`WUD_WATCHER_DOCKER_LOCAL_WATCHBYDEFAULT=true` discovers running containers that pass the filter. Set it to `false` for opt-in monitoring, then add `wud.watch: "true"` to each monitored service's Docker labels. A `wud.watch: "false"` label excludes a container. These labels belong on the services being monitored, not in WUD's Environment tab. + +Stopped containers are excluded by default. Set `WUD_WATCHER_DOCKER_LOCAL_WATCHALL=true` to include them. Optional include/exclude patterns, tag filters, digest tracking, and release links are covered in [environment.md](environment.md) and the [container label guide](https://getwud.app/docs/configuration/watchers/labels/). + +Only the proxy mounts `/var/run/docker.sock`. This system socket is the intentional host bind mount; it must already exist on a normal Linux Docker host. WUD connects to `wud-socket-proxy:2375`, with container/image reads and Docker events allowed. `POST=0` blocks write methods, including container start/stop, exec, image pulls, and deletion. A read-only socket mount alone would not block those Docker API operations. + +Container inspection can expose host workload metadata and environment values, so keep proxy access within the isolated stack. Do not expose port 2375 or broaden proxy permissions for normal monitoring. This template observes one Docker host; it does not automatically discover remote Dokploy servers or configure a Swarm/Kubernetes watcher. + +## Notifications and updates + +Add notification variables in Dokploy's Environment tab, then redeploy. WUD loads optional values from `.env`. For example, an optional Ntfy trigger needs: + +```dotenv +WUD_TRIGGER_NTFY_ALERTS_URL=https://ntfy.sh +WUD_TRIGGER_NTFY_ALERTS_TOPIC=your-private-topic +``` + +Use your server's authentication settings where needed. See the official [trigger documentation](https://getwud.app/docs/configuration/triggers/) for supported providers and required credentials. No notification provider is required to install WUD. + +Watcher, registry, and trigger settings are configured through the environment; their configuration pages in WUD display the effective settings. User accounts, preferences, and API tokens can be managed in the app. + +The template does not configure Docker or Docker Compose update triggers. Keep changes to Dokploy-managed applications in Dokploy so its deployment configuration stays authoritative. Adding an updater would require a separate, deliberate change to the proxy permissions and deployment design. Triggers can run automatically when configured; do not add a Docker updater merely to test notifications. + +## Passwords, persistence, and backups + +WUD reapplies `WUD_AUTH_ADMIN_USER` and `WUD_AUTH_ADMIN_PASSWORD` on every startup, including an existing account. Rotate this administrator's password in Dokploy's Environment tab and redeploy. Changing only that account's password in WUD will be overwritten on the next restart. Additional users are stored in the database and can be managed in WUD. + +The `wud-data` volume stores `/store`, including `wud.sqlite`, its WAL files, users, token hashes, preferences, monitored containers, history, and snoozes. Keep one WUD instance per volume. Back up the complete volume while WUD is stopped, or use a SQLite-aware backup method. Copying only the live `wud.sqlite` file can miss recent writes in the WAL. Keep an off-server copy and protect it as sensitive data. + +The official image handles store creation and migrations. It runs as root; this template drops all Linux capabilities and prevents privilege escalation. Do not force a different UID without preparing and checking volume ownership. Back up before changing the pinned image version and review the [release notes](https://github.com/getwud/wud/releases). + +### HTTPS and health behavior in 9.5.0 + +Use HTTPS and HTTP redirection for regular access. WUD 9.5.0 sets an HttpOnly session cookie, but its upstream implementation does not add Secure or SameSite cookie attributes. This template does not modify the published application image. You may need to sign in again after a container recreation or upgrade because WUD derives its session secret from the version and network interface. + +GET `/health` is public HTTP liveness. It does not prove that Docker discovery or registry checks succeeded: also check the local watcher, discovered containers, and scan errors. The API and dashboard require authentication. + +See [environment.md](environment.md) for settings and [testing.md](testing.md) for verification steps. diff --git a/blueprints/wud/meta.json b/blueprints/wud/meta.json new file mode 100644 index 00000000..80cd5417 --- /dev/null +++ b/blueprints/wud/meta.json @@ -0,0 +1,13 @@ +{ + "id": "wud", + "name": "WUD (What's Up Docker?)", + "version": "9.5.0", + "description": "WUD monitors Docker containers for image updates and shows available versions in a web dashboard. This template includes administrator authentication, persistent storage, and a Docker socket proxy that blocks write requests.", + "logo": "wud.svg", + "links": { + "github": "https://github.com/getwud/wud", + "website": "https://getwud.app/", + "docs": "https://getwud.app/docs/quickstart/" + }, + "tags": ["monitoring", "docker", "devops"] +} diff --git a/blueprints/wud/template.toml b/blueprints/wud/template.toml new file mode 100644 index 00000000..e7375831 --- /dev/null +++ b/blueprints/wud/template.toml @@ -0,0 +1,20 @@ +[variables] +main_domain = "${domain}" +admin_password = "${hash:48}" + +[config] +env = [ + "WUD_AUTH_ADMIN_USER=admin", + "WUD_AUTH_ADMIN_PASSWORD=${admin_password}", + "WUD_WATCHER_DOCKER_LOCAL_WATCHBYDEFAULT=true", + "WUD_WATCHER_DOCKER_LOCAL_EXCLUDE=^dokploy([._-]|$)", + "WUD_WATCHER_DOCKER_LOCAL_WATCHALL=false", + "WUD_WATCHER_DOCKER_LOCAL_CRON=0 * * * *", + "WUD_LOG_LEVEL=info", + "TZ=UTC" +] + +[[config.domains]] +serviceName = "wud" +port = 3000 +host = "${main_domain}" diff --git a/blueprints/wud/testing.md b/blueprints/wud/testing.md new file mode 100644 index 00000000..594b919f --- /dev/null +++ b/blueprints/wud/testing.md @@ -0,0 +1,15 @@ +# Testing WUD + +Use a disposable Dokploy instance and synthetic workloads. Do not apply update triggers to production containers during template verification. + +1. Run the repository's metadata, Compose, and TOML validators and build the catalog. Confirm that only the new blueprint files changed. +2. Import the Base64 configuration from the PR preview into a fresh Dokploy Compose service. Enable isolated deployment, retain the generated credentials, and deploy without registry or notification credentials. +3. Check both service health states. Anonymous GET `/health` should return 200, while `/api/containers` must return 401 and the dashboard must require login. Verify wrong-password rejection and successful login. +4. Inspect the effective local watcher: host `wud-socket-proxy`, port `2375`, exclusion `^dokploy([._-]|$)`. Scan with disposable workloads named like Dokploy infrastructure and an ordinary application: matching `dokploy` names should be absent while the application remains monitored. Remove the exclusion from Environment, redeploy, and click **Watch now**: the previously excluded workloads should appear. Also verify that `wud.watch=true` can opt in a matching container. Health alone does not verify scanning. Confirm that no update triggers are registered. +5. From inside the isolated stack, check the proxy: GET `/_ping`, `/containers/json`, and `/images/json` should work. Requests to disabled groups such as `/volumes` and Docker write requests should return 403. Use a disposable nonexistent container ID for a stop request, then verify real containers are unchanged. The WUD container must have no Docker socket mount. +6. Change a preference, create a read-only test user, issue a read-scoped API token, and snooze a discovered container. Recreate WUD through Dokploy while preserving its volume. Sign in again if necessary and verify the user, preference, token, snooze, and stored container records survive. +7. In the disposable installation, change the bootstrap administrator's password only in WUD, restart, and verify that the Environment value is reapplied. Then rotate it through Dokploy and confirm the new value works. Additional users must remain intact. +8. Exercise opt-in monitoring with `WATCHBYDEFAULT=false` and a `wud.watch=true` workload. If testing notifications, use a local mock endpoint and assert its received payload rather than sending real messages. Keep Docker write access blocked throughout. +9. Enable HTTPS in Dokploy and verify login, API access, dashboard assets, and live events through Traefik. Check browser errors and server logs. Record the upstream cookie behavior described in [instructions.md](instructions.md); do not claim Secure/SameSite flags that the application does not set. + +Record image tags, Dokploy version, registry results, tested optional providers, and any limits in the PR. Use synthetic data in screenshots. Public certificate issuance and every external notification/registry provider require separate checks. Remove only the disposable test resources after collecting evidence. diff --git a/blueprints/wud/wud.svg b/blueprints/wud/wud.svg new file mode 100644 index 00000000..ca76e7a6 --- /dev/null +++ b/blueprints/wud/wud.svg @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +