Infisical self-hosted setupWhat you get. What breaks. What to plan for.
Infisical gives you a proper secrets manager with a web UI, audit logs, and a usable CLI without paying a SaaS bill. Getting it running takes an afternoon. Keeping it running takes a plan.
-
01
State
Env vars in shell
Secrets in ~/.zshrc or .env, readable by any child process
ambient, always-on -
02
Method
docker-compose + infisical run
Stack boots, CLI fetches secrets, injects at exec time
3 services: pg, redis, app -
03
Result
Secrets injected at exec
Child process sees values; parent shell does not
audit log records each fetch
TL;DR· the answer, in twenty seconds
What: Infisical is an MIT-licensed secrets manager you can run on your own infrastructure. The core stack is Postgres, Redis, and the Infisical container. The web UI, CLI, machine identities, and audit logs are all included in the open-source build.
Setup path: Clone the repo, copy docker-compose.yml, set env vars, run docker compose up -d, create the first admin user through the web UI, then authenticate the CLI with infisical login.
Lesson: Self-hosting a secrets manager shifts the problem, not the risk. You still need a backup strategy for the encrypted Postgres database, a plan for the root encryption key, and an answer to the secret-zero problem every service token creates.
Infisical is the self-hosted secrets manager that most teams land on after they decide Vault is too much ops and HashiCorp Vault's licensing changes made them nervous. The MIT-licensed core covers the things you actually need day-to-day: a web UI for browsing and editing secrets, a CLI that can inject secrets at process execution time, machine identities for services and CI runners, secret versioning, and an audit log. Enterprise features like SAML SSO, secret rotation connectors, and advanced RBAC sit behind a paid license, but you can run a real production workflow without them.
This guide walks through a full self-hosted setup: Docker Compose configuration, first-run admin setup, CLI authentication, service token issuance, and integrating with apps via infisical run. The second half covers what can go wrong, which is where most writeups stop too early.
GitGuardian's State of Secrets Sprawl 2026 found that AI-assisted commits leak credentials at roughly twice the baseline rate. If you're using a coding agent in your workflow, a self-hosted secrets manager you understand and control is a reasonable response. But "self-hosted" adds complexity you have to budget for.
What you get in 60 seconds
- Docker Compose stack: Postgres 14, Redis 7, Infisical container. Three moving parts.
- Web UI on port 8080 for browsing secrets, managing projects, inviting team members.
infisical run -- <cmd>injects secrets from a project into one child process's environment. Same pattern asdoppler run --.- Machine identities replace service tokens for CI and services. They use short-lived JWTs rather than long-lived static strings.
- Audit log records every secret read, write, and delete with caller identity and timestamp.
- MIT license on the core. No call-home, no account requirement, no usage limits.
- The encrypted vault lives in Postgres. The encryption key lives in an env var you set at startup.
Stand up the stack
Clone the Infisical repo and copy the example Compose file:
git clone https://github.com/Infisical/infisical.git
cd infisical
cp .env.example .env
Open .env. The fields you need to set before first boot:
# Generate with: openssl rand -hex 32
ENCRYPTION_KEY=your-32-byte-hex-key-here
# JWT signing; generate separately
AUTH_SECRET=your-auth-secret-here
# Site URL - used in email links and CORS
SITE_URL=https://secrets.yourcompany.com
# Postgres connection (matches the pg service in docker-compose.yml)
DB_CONNECTION_URI=postgresql://infisical:infisical@postgres:5432/infisical
# Redis
REDIS_URL=redis://redis:6379
The ENCRYPTION_KEY is the root key for the vault. Every secret stored in Postgres is encrypted with a key derived from this value. Write it down. Store it somewhere separate from the Compose file. If you lose it, your secrets are gone. There is no recovery path.
The default docker-compose.yml in the repo is production-oriented and includes a migration service that runs schema migrations on startup. Boot the stack:
docker compose up -d
After 30-60 seconds, Postgres finishes initializing, migrations run, and the Infisical container starts. Check:
docker compose ps
docker compose logs infisical --tail 50
You should see Server started on port 8080. Open http://localhost:8080 (or your configured domain) to create the first admin user.
Configure your first project
After the admin user is created, the web UI walks you through creating an organization and a project. Projects are the unit of access control. Each project has its own set of secrets, members, and environments (development, staging, production by default).
Create a project, then add a few secrets through the UI. The UI has a good search and a clean diff view when you edit values.
For the CLI, install it:
# macOS
brew install infisical/get-cli/infisical
# Linux
curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | sudo bash
sudo apt-get install infisical
Authenticate against your self-hosted instance:
infisical login --domain https://secrets.yourcompany.com
This opens a browser window, authenticates via the Infisical web UI, and writes a session token to ~/.infisical/. From that point the CLI knows which instance to talk to.
Connect a local project:
cd your-app
infisical init
infisical init asks which project and environment to link, then writes a .infisical.json to the project root. Commit this file. It contains only the project ID and environment name, no secret values.
Run services with secrets injected at exec time
The main integration pattern is infisical run:
infisical run -- node server.js
infisical run --env staging -- python manage.py runserver
infisical run --projectId abc123 --env production -- ./my-binary
This fetches secrets from the linked project and environment, sets them as environment variables for the child process only, then runs the command. The parent shell does not see the values. When the child exits, the values are gone.
For CI, you want machine identities rather than a personal auth token. In the web UI, go to Project Settings > Machine Identities, create an identity, and attach it to a role. Then create a Universal Auth credential for it. This gives you a client ID and client secret.
In CI:
export INFISICAL_CLIENT_ID=your-client-id
export INFISICAL_CLIENT_SECRET=your-client-secret
infisical run \
--projectId your-project-id \
--env production \
--machine-identity-id your-identity-id \
-- ./deploy.sh
For apps that can not run under infisical run (long-running daemons, systemd units, Docker containers), use the Infisical SDK directly. SDKs exist for Node.js, Python, Go, Ruby, Java, and .NET. The Go SDK:
import infisical "github.com/infisical/go-sdk"
client, err := infisical.NewInfisicalClient(context.Background(), infisical.Config{
SiteUrl: "https://secrets.yourcompany.com",
Auth: infisical.AuthConfig{
UniversalAuth: &infisical.UniversalAuthConfig{
ClientId: os.Getenv("INFISICAL_CLIENT_ID"),
ClientSecret: os.Getenv("INFISICAL_CLIENT_SECRET"),
},
},
})
secret, err := client.Secrets().Retrieve(infisical.RetrieveSecretOptions{
SecretKey: "DATABASE_URL",
Environment: "production",
ProjectID: "your-project-id",
})
The SDK caches secrets locally and refreshes on TTL. It retries on network error. For most services, this works better than trying to fit a long-running daemon under infisical run.
What can go wrong
The backup problem
Your secrets are encrypted in Postgres. If the Postgres container gets corrupted, migrated wrong, or the volume gets deleted, you lose the ciphertext. If you separately lose the ENCRYPTION_KEY, you lose the plaintext too. Both disasters need independent solutions.
Back up Postgres with pg_dump, scheduled via cron or a sidecar. Store the dumps somewhere that isn't the same machine as the Compose stack. Three replicas of a backup on the same disk is zero backups.
Store the ENCRYPTION_KEY in a separate system: a password manager, a hardware token, or a second encrypted store that your team can access independently of the Infisical instance. Document the recovery procedure. Run it once in a staging environment to confirm it works.
Key rotation
Infisical does not support root encryption key rotation in the MIT build as of early 2026. If you suspect the ENCRYPTION_KEY was exposed, your options are: rotate all the secrets stored in the vault (which you should do anyway), then set up a fresh Infisical instance with a new key and migrate secrets through the CLI. There is no in-place key rotation command.
This is a real limitation. Plan for it before you put anything sensitive in the vault.
Redis dependency
Redis stores session data and job queues. If Redis goes down, the web UI stops accepting new logins. Running infisical run for short-lived processes still works if the CLI session token is still valid, but the UI will not function. Run Redis with appendonly yes and consider a separate backup for the Redis AOF file if session continuity matters.
The secret-zero problem
infisical run still needs credentials to authenticate with the Infisical instance. For CI, that's INFISICAL_CLIENT_ID and INFISICAL_CLIENT_SECRET. Those two values live in your CI provider's secret store, which is another secrets manager. You have shifted the secret-zero from "all my secrets in one env file" to "two credentials that unlock all my secrets." That is an improvement, not a solution.
For machine identities with short-lived tokens, the blast radius is smaller than a static API key. A compromised JWT expires within minutes. A compromised static service token lasts until you revoke it, which you might not know to do.
Audit log gives you forensics, not prevention
The Infisical audit log records every secret read with caller identity, IP, and timestamp. If a CI runner was compromised and fetched your production DATABASE_URL at 3am, the audit log shows that. After the fact. The audit log does not stop a valid credential from fetching a secret it has access to. Scope machine identities tightly to the minimum set of secrets they need. Review access grants periodically.
What the conventional take gets wrong
Most Infisical setup guides stop after docker compose up and a working infisical run. They leave out the operational surface you just acquired.
You now run Postgres. You need a backup, a restore test, and a plan for schema migrations when you upgrade Infisical. Upgrading the Infisical container sometimes requires running migrations before the new container will boot. Read the release notes before pulling a new image.
You now run Redis. Redis by default does not persist to disk. A container restart without appendonly yes drops all in-flight session data.
You run the Infisical container itself, which needs TLS in front of it for anything beyond local development. The repo's example Nginx config works. So does Caddy with automatic HTTPS. Do not run the API on plain HTTP if any client is off-localhost.
The "three moving parts" framing is accurate. Infisical is meaningfully simpler than Vault. It is not simpler than a SaaS secrets manager where someone else handles the Postgres backup and the TLS cert renewal. That tradeoff is fine if you have the ops capacity. Be honest about whether you do.
Checklist for a production Infisical setup
## Infisical self-hosted production checklist
- [ ] ENCRYPTION_KEY generated with openssl rand -hex 32
- [ ] ENCRYPTION_KEY stored in a separate system (password manager, hardware token)
- [ ] AUTH_SECRET generated separately from ENCRYPTION_KEY
- [ ] .env file excluded from version control
- [ ] TLS termination configured (Nginx or Caddy in front of port 8080)
- [ ] Postgres volume mapped to a named Docker volume or host path
- [ ] pg_dump cron configured; dumps stored off-machine
- [ ] Restore procedure documented and tested once
- [ ] Redis appendonly yes set in Redis config
- [ ] Machine identities created for each CI runner and service (no shared credentials)
- [ ] Machine identity roles scoped to minimum required secrets
- [ ] .infisical.json committed to each connected repo
- [ ] infisical run used for short-lived processes; SDK used for daemons
- [ ] Audit log retention period confirmed (Postgres-backed, grows unbounded)
- [ ] Infisical upgrade path tested in staging before production
- [ ] Nginx/Caddy TLS cert renewal automated and monitored
- [ ] Incident plan documented: what to do if ENCRYPTION_KEY is suspected exposed
What this means for your stack
Self-hosting Infisical is a reasonable call if you want a dashboard, audit logs, and per-project access control without a SaaS dependency. The MIT core covers most of what a team of 2-20 engineers needs. The setup is a half-day, not a week. The gap between "running" and "production-ready" is the backup story, the key management plan, and the TLS configuration, none of which the quickstart docs cover adequately.
The category problem underneath this is that every secrets manager, self-hosted or otherwise, still relies on a bootstrap secret: the credentials your CI runner uses to fetch the rest. Infisical narrows that to two values (client ID and client secret) with short-lived tokens, which is better than a dozen .env files. But if your threat model includes a compromised CI runner or a compromised developer machine, the secrets manager alone does not close the gap.
hasp takes a different angle on the same problem. curl -fsSL https://gethasp.com/install.sh | sh, hasp setup, bind a project, and the next session's agent gets a scoped reference instead of a value it can exfiltrate. Source-available (FCL-1.0), local-first, macOS and Linux, no account, no cloud, no Postgres to back up.
The durable principle is the same either way. Long-lived ambient credentials are the unsafe surface. Infisical reduces how many of them exist. A runtime broker reduces what any one agent or process can do with the ones that remain.
Sources· cited above, in one place
Stop handing the agent your real keys.
hasp keeps secrets in one local encrypted vault, brokers them into the child process at exec, and never lets the agent read the value.
- Local, encrypted vault — no account, no cloud, no telemetry by default.
- Brokered run — agent gets a reference, the child process gets the value.
- Pre-commit + pre-push hooks catch managed values before they ship.
- Append-only HMAC audit log answers "did the agent touch the prod token?" in seconds.
macOS & Linux. Source-available (FCL-1.0, converts to Apache 2.0). No account.