# SSH / Unraid deployment ForgeFlow deploys an exact Gitea commit directly to an Unraid server over pinned SSH. ## Security model - Credentials are entered only in the local ForgeFlow desktop application. - Ed25519 private keys are preferred. - Passwords and key passphrases use Electron safe storage. - The first trusted connection records the SSH host-key fingerprint; later changes fail closed. - Unraid-to-Gitea repository access is tested during every deployment preflight. - The renderer cannot submit arbitrary shell commands. Remote scripts are assembled from validated profile fields and transported as base64-encoded Bash input. - Tracked server-side modifications block deployment and rollback. ## Profile identity ForgeFlow separates names that users see from names Docker requires: ```text Visible project/container: Portfolio Server folder: Portfolio Internal Compose project: portfolio Internal Compose service: portfolio Internal image: forgeflow/portfolio:production ``` The internal Compose service must match the repository's service key and remain lowercase. The visible container can preserve branding and casing. ## DockerMan WebUI, icon and shell ForgeFlow writes `.forgeflow/compose.metadata.yml` and combines it with the repository or generated Compose file. The override supplies: ```text net.unraid.docker.managed=dockerman net.unraid.docker.webui=http://[IP]:[PORT:]/ net.unraid.docker.icon= net.unraid.docker.shell=sh ``` Icon modes: - **Built-in high-contrast ITWorx mark** — default; - **Upload local PNG** — copied to `/boot/config/plugins/dockerMan/images/-icon.png`; - **Use icon URL** — HTTP(S) PNG; - **No custom icon**. After metadata changes ForgeFlow recreates the container, writes `/boot/config/plugins/dockerMan/templates-user/my-.xml`, removes known icon caches and invalidates DockerMan's volatile `docker.json` metadata cache. The Unraid Docker page may still need one browser refresh. The deployment card reports whether WebUI and icon labels were confirmed through `docker inspect`. **Repair DockerMan integration** recreates an existing healthy container with labels, a persistent DockerMan template, icon cache refresh and WebUI metadata without creating a Git commit. **Open Web UI** uses the profile URL directly from the desktop. ## Existing application folder For an existing folder: ```text Server folder: Portfolio Remote path: /mnt/user/appdata/Portfolio Compose file: docker-compose.yml ``` The project root must be a Git working tree. Untracked runtime paths such as `.env`, `appdata`, `data`, `logs`, `config` and `compose.override.yml` remain untouched by `git reset --hard`. Nested Git repositories are warnings and never deleted automatically. Preflight inspects `.dockerignore` when a Dockerfile exists. It warns when `.git`, preserved runtime data or nested repositories would be sent into the build context. ## New application folder The server clones the configured URL on the selected branch. The Unraid host therefore needs a non-interactive Gitea SSH identity. Preflight runs `git ls-remote --exit-code` from Unraid before deployment. Use repository Compose for real applications. Generated Compose is intended only for a simple single-service Dockerfile application with basic port mapping. ## Deployment sequence 1. Verify clean local tree, allowed branch, upstream and ahead/behind state. 2. Verify the exact SHA exists on the allowed remote branch. 3. Verify Unraid can read the Gitea repository. 4. Inspect the server folder and refuse tracked server changes. 5. Clone when the folder is absent. 6. Fetch the branch and verify the exact SHA is an ancestor of `origin/`. 7. Save the previous SHA and reset to the requested SHA. 8. Write generated Compose when selected. 9. Write the DockerMan metadata override and persistent template fallback. 10. Validate the merged Compose model. 11. Run `docker compose up -d --build --remove-orphans --force-recreate`. 12. Clear relevant icon caches. 13. Inspect the visible container and write `.forgeflow/status.json`. 14. Run the configured desktop healthcheck. 15. Persist the live SHA, previous SHA, health, container and DockerMan state. ## Interrupted operation recovery At startup and through **Reconcile**, ForgeFlow reads the live SHA, container running state, Docker health, labels and persistent template state. When a previously running operation already reached its exact requested SHA and the container is healthy, the operation becomes `success`. Operations that remain unresolved for more than 45 minutes become `failed` rather than staying indefinitely in deployment mode. ## Rollback Rollback is accepted only for the exact SHA currently recorded as `previousSha`. ForgeFlow re-verifies that commit against Gitea, refuses tracked server changes, resets the same working tree, reapplies Compose and DockerMan metadata, reruns health checks and rotates the former live SHA into the new rollback target.