# Infisical (Secrets Management) Self-hosted Infisical instance running as a Docker stack on [DOCKER](docker.md) (10.100.0.35). Deployed via Ansible (role `infisical` in the [ansiblearr](https://github.com/dohejw01/ansiblearr) playbook); deployed 2026-04-29. ## Access - **URL**: https://infisical.dohertylan.com (via Traefik + Cloudflare cert) - **Auth**: native Infisical accounts (no Authelia middleware — Infisical has its own login) - **First-time setup**: first sign-up becomes the admin. After bootstrapping, set `INVITE_ONLY_SIGNUP=true` in `roles/infisical/defaults/main.yml` and re-deploy to lock further signups. ## Stack layout (on docker host) `/opt/infisical/` (compose project name `infisical`; service labels carry standard `com.docker.compose.*` only — no custom `project=lmxopcua`-style label): | Container | Image | Internal port | Host port | Volume | |---|---|---|---|---| | `infisical` | `infisical/infisical:latest-postgres` | 8080 (HTTP) | none — Traefik handles 443→8080 | — | | `infisical-db` | `postgres:16-alpine` | 5432 | none | `/opt/infisical/postgres_data` | | `infisical-redis` | `redis:7-alpine` | 6379 | none | `/opt/infisical/redis_data` | Networks: `traefik` (external, shared with the rest of the stack) and `infisical` (internal-only bridge for db + redis). ## Configuration Source of truth: `roles/infisical/defaults/main.yml` in the ansible repo. Re-deploys overwrite `/opt/infisical/docker-compose.yml`, so don't edit it on the host. | Variable | Value (default) | Notes | |---|---|---| | `infisical_image` | `infisical/infisical:latest-postgres` | Standalone all-in-one image (API + frontend) | | `infisical_subdomain` | `infisical` | Becomes `infisical.dohertylan.com` | | `infisical_db_user` / `_db_name` | `infisical` / `infisical` | Internal-only — not exposed past the compose network | | `infisical_db_password` | `[Infisical: homelab/apps/infisical/DB_PWD]` | Plaintext also lives in `roles/infisical/defaults/main.yml` (chicken-and-egg: the playbook must hold the value to deploy Infisical from scratch) | | `infisical_encryption_key` | 32 hex chars | **Do not change after data exists** — used to envelope-encrypt secrets at rest. Changing it makes existing secrets unrecoverable; use Infisical's key-rotation flow if you need to rotate | | `infisical_auth_secret` | random base64 | JWT signing key | | `infisical_telemetry_enabled` | `false` | Anonymous telemetry opted out | ## Deploy / update Three equivalent paths: ```bash # Via Semaphore UI (or API): http://10.100.0.35:3000 → template "Deploy Full Stack" curl -s -c - http://localhost:3000/api/auth/login -X POST -H 'Content-Type: application/json' \ -d '{"auth":"dohertj2","password":""}' | grep semaphore | awk '{print $NF}' \ | xargs -I{} curl -s -b "semaphore={}" -X POST http://localhost:3000/api/project/1/tasks \ -H 'Content-Type: application/json' -d '{"template_id":8,"project_id":1}' # Or directly on the docker host (skips going through Semaphore/git): ssh dohertj2@10.100.0.35 'cd /opt/infisical && docker compose up -d' # Or pull image only (without restart): ssh dohertj2@10.100.0.35 'cd /opt/infisical && docker compose pull' ``` To make a change, edit `roles/infisical/defaults/main.yml` (or the template), commit + push to GitHub, then re-run the Semaphore template. ## Operations ```bash # Status ssh dohertj2@10.100.0.35 'docker ps --filter name=infisical' # Logs ssh dohertj2@10.100.0.35 'cd /opt/infisical && docker compose logs --tail=200 infisical' # Restart just the app (keep db/redis up) ssh dohertj2@10.100.0.35 'cd /opt/infisical && docker compose restart infisical' # Full stack restart ssh dohertj2@10.100.0.35 'cd /opt/infisical && docker compose up -d --force-recreate' # psql shell into the db ssh dohertj2@10.100.0.35 'docker exec -it infisical-db psql -U infisical -d infisical' ``` ## Backups Only state worth preserving: `/opt/infisical/postgres_data`. Redis is just a cache. ```bash # Hot logical dump (run on docker host) docker exec infisical-db pg_dump -U infisical -d infisical | gzip > /mnt/share/backups/infisical-$(date +%F).sql.gz ``` Restore: stop the stack, drop and recreate the DB, `gunzip < dump.sql.gz | docker exec -i infisical-db psql -U infisical -d infisical`, start the stack. Whatever encryption key was in `defaults/main.yml` at backup time must still be in place — the restored ciphertext is only readable with the same `ENCRYPTION_KEY`. ## Client setup (CLI on other machines) Goal: from any host that needs a credential, run `infisical secrets get …` (or `infisical run -- `) instead of finding the value in a `.md` file. ### 1. Create a per-host Machine Identity One per host — never share. Each is independently revocable and shows up cleanly in the audit log. 1. https://infisical.dohertylan.com → **Org Settings → Access Control → Identities → Add** 2. Name it `claude-` (e.g., `claude-mac`, `claude-ww-vm`, `claude-docker`). Auth method: **Universal Auth**. 3. Open the new identity → **Client Secrets** → **Create Client Secret** → save the `client_id` + `client_secret` (only shown once). 4. (Optional but recommended) Open the identity → **Authentication → Universal Auth** → set **Client Secret Trusted IPs** to `10.100.0.0/24` so the credential is unusable off-LAN. 5. Open the **Homelab** project → **Access Control → Identities → Add** → pick the new identity, role **Viewer** (read-only). Promote to Developer/Admin only if the host needs to write secrets. ### 2. Install the CLI **Linux (Debian/Ubuntu/Trixie):** ```bash curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | sudo -E bash sudo apt-get install -y infisical ``` **macOS:** ```bash brew install infisical/get-cli/infisical ``` **Windows (PowerShell, admin):** ```powershell winget install --id Infisical.InfisicalCLI -e # or: scoop bucket add main; scoop install infisical ``` Verify with `infisical --version`. ### 3. Configure auth + endpoint The CLI reads `INFISICAL_API_URL` for the host (defaults to Infisical Cloud — must be overridden for self-hosted) and either env vars or a saved login for credentials. Recommended: env vars in your shell rc / Windows user env. **Linux/macOS** (`~/.bashrc`, `~/.zshrc`): ```bash export INFISICAL_API_URL=https://infisical.dohertylan.com export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID="" export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET="" ``` **Windows** (PowerShell — sets persistent user env): ```powershell [Environment]::SetEnvironmentVariable('INFISICAL_API_URL','https://infisical.dohertylan.com','User') [Environment]::SetEnvironmentVariable('INFISICAL_UNIVERSAL_AUTH_CLIENT_ID','','User') [Environment]::SetEnvironmentVariable('INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET','','User') # Open a new shell for these to take effect. ``` Each `infisical` command will use Universal Auth automatically when these are set. No `infisical login` needed. ### 4. Verify ```bash # Should print one or more secrets from the homelab project infisical secrets --env=infrastructure --path=/esxi --silent # Get a single value (the GOVC password): infisical secrets get GOVC_PASSWORD --env=infrastructure --path=/esxi --plain # Run a command with secrets injected as env vars: infisical run --env=infrastructure --path=/esxi -- printenv GOVC_PASSWORD ``` If the project ID can't be resolved automatically, pin it: ```bash infisical secrets get GOVC_PASSWORD \ --projectId=e36459c8-b071-4b86-a43c-795b31e75584 \ --env=infrastructure --path=/esxi --plain ``` ### 5. Common usage patterns ```bash # govc — fetch the password into env via `infisical run`, no plaintext on disk infisical run --env=infrastructure --path=/esxi -- \ bash -c 'GOVC_URL=https://10.2.0.12/sdk GOVC_USERNAME=govc GOVC_INSECURE=true \ govc vm.info WW_DEV_VM' # .NET app reads SQL_DEV_SA_PWD from env at startup infisical run --env=dev --path=/lmxopcua -- \ dotnet run --project src/ZB.MOM.WW.OtOpcUa.Server # Docker compose with secret env injection infisical run --env=apps --path=/gitea -- docker compose up -d # Shell into one secret quickly: PWD=$(infisical secrets get WW_VM_ADMIN_PWD --env=infrastructure --path=/windows-hosts --plain) sshpass -p "$PWD" ssh dohertj2@10.100.0.48 hostname ``` ### 6. For Claude Code specifically Claude can shell out to `infisical` like any other CLI tool. To make the pointer syntax in our docs (`[Infisical: homelab///]`) directly executable, drop this one-liner alias / function in your shell rc: ```bash secret() { # secret // local arg=$1 env="${arg%%/*}" rest="/${arg#*/}" key="${rest##*/}" folder="${rest%/*}" infisical secrets get "$key" --env="$env" --path="${folder:-/}" --plain } ``` Now `secret infrastructure/esxi/GOVC_PASSWORD` returns the value, matching the doc pointer 1:1. ### 7. (Optional) Infisical MCP server for Claude Code For native tool access (instead of shell-out), add an MCP server to `~/.claude/mcp.json`. The community package's name and exact config can shift — check the latest before depending on it. Outline: ```jsonc { "mcpServers": { "infisical": { "command": "npx", "args": ["-y", "@infisical/mcp-server"], "env": { "INFISICAL_HOST": "https://infisical.dohertylan.com", "INFISICAL_CLIENT_ID": "", "INFISICAL_CLIENT_SECRET": "", "INFISICAL_PROJECT_ID": "e36459c8-b071-4b86-a43c-795b31e75584" } } } } ``` Restart Claude Code and `mcp__infisical__*` tools will be available. ## Homepage entry Listed under the **Infrastructure** group on https://home.dohertylan.com — icon `infisical.png` (from dashboard-icons), URL `https://infisical.dohertylan.com`, description "Secrets Management". Added in `roles/homepage/defaults/main.yml`. ## Risks / gotchas - **`ENCRYPTION_KEY` is the master**. Treat changes to that var as a destructive operation. The default is checked into git in the private ansiblearr repo — fine while the repo stays internal; rotate immediately if it ever goes public. - **First sign-up gets admin** with no out-of-band gating. Sign up immediately after the initial deploy so a passing scanner doesn't beat you to it. - **No Authelia middleware**. Infisical's own auth is the only thing in front of the API — exposed via Cloudflare to the internet at `infisical.dohertylan.com`. Enable Infisical SSO + MFA before storing anything sensitive. - **Single-instance**. Postgres + Redis run alongside the app on one box. Acceptable for a homelab; not HA. If the docker host goes down, secrets API is unavailable — plan integrations accordingly (don't make Infisical a hard dependency for things that need to recover during a docker host outage).