docs/integrations/platforms/docker.mdx
import ConfigureProject from "/snippets/documentation/platform/secrets-mgmt/configure-project.mdx";
This guide walks you through storing secrets in Infisical and injecting them into a Dockerized application as environment variables. You can fetch secrets when the container starts or export them from the host when you run the container.
<Tip> Visual learner? Watch an [overview of managing secrets in Docker with Infisical](https://www.youtube.com/watch?v=oU2nNBwlOTA). </Tip> <Info> Prerequisites:Next, choose how Docker should receive your application secrets:
<Tabs> <Tab title="Fetch at startup (Recommended)"> <span id="fetch-at-startup"></span>This method installs the Infisical CLI in your image and uses it to start your application. The CLI fetches secrets when the container starts and injects them into the application process.
<Note>
We strongly recommend this method, since it works for both local development and automated/production environments.
</Note>
### Create a machine identity
Create a [machine identity](/documentation/platform/identities/machine-identities) for your application:
<Steps>
<Step>
In your project, select **Project Settings** > **Access Control** > **Machine Identities**.
</Step>
<Step>
Select **Add Machine Identity**, then select **Create New**.
</Step>
<Step>
Enter a name (e.g., `orders-service-docker`), select a role that can read secrets, and select **Create**.
</Step>
</Steps>
Infisical creates the identity with [Universal Auth](/documentation/platform/identities/universal-auth) enabled and opens its details page.
### Create a client secret
Create credentials that the application can exchange for a short-lived access token:
<Steps>
<Step>
In the machine identity's **Authentication** section, select **Universal Auth**.
</Step>
<Step>
Copy the **Client ID** and save it somewhere secure for the next step.
</Step>
<Step>
Select **Create Client Secret**, enter a description (e.g., `docker-quickstart`), and select **Create**.
</Step>
<Step>
Copy the **Client Secret**. You won't be able to view it again.
</Step>
</Steps>
<Warning>
Don't add the Client ID, Client Secret, or an Infisical access token to your Dockerfile. Docker images may be shared or stored in a registry.
</Warning>
<Note>
Machine identity access tokens are short-lived. Token expiration doesn't affect an application after `infisical run` has fetched its secrets, but the container needs a valid token every time it starts.
In automated deployments, store the Client ID and Client Secret in your deployment platform's secret store and run `infisical login` immediately before each `docker run` or `docker compose up`.
</Note>
### Copy your project ID
In your project, select **Project Settings**, then select **Copy Project ID**. You'll add this ID to your Dockerfile in the next step.
### Update your Dockerfile
Add the Infisical CLI installation that matches your base image:
<CodeGroup>
```dockerfile Alpine
RUN apk add --no-cache bash wget \
&& wget -qO- 'https://artifacts-cli.infisical.com/setup.apk.sh' | sh \
&& apk add --no-cache infisical
```
```dockerfile Debian or Ubuntu
RUN apt-get update \
&& apt-get install -y --no-install-recommends bash curl ca-certificates \
&& curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
&& apt-get update \
&& apt-get install -y --no-install-recommends infisical \
&& rm -rf /var/lib/apt/lists/*
```
</CodeGroup>
<Tip>
Pin the [Infisical CLI version](https://github.com/Infisical/cli/releases) in production images to keep builds reproducible.
</Tip>
Next, wrap your application's start command with [`infisical run`](/cli/commands/run). Replace `<project-id>` with the project ID you copied earlier:
<CodeGroup>
```dockerfile Node.js
CMD ["infisical", "run", "--projectId=<project-id>", "--env=dev", "--", "npm", "start"]
```
```dockerfile Flask
CMD ["infisical", "run", "--projectId=<project-id>", "--env=dev", "--", "flask", "run", "--host=0.0.0.0"]
```
```dockerfile Go
CMD ["infisical", "run", "--projectId=<project-id>", "--env=dev", "--", "./app"]
```
</CodeGroup>
<Accordion title="Run multiple startup commands">
Use the [`--command` option](/cli/commands/run#infisical-run:command) when your application needs to run multiple shell commands in sequence:
```dockerfile
CMD ["infisical", "run", "--projectId=<project-id>", "--env=dev", "--command", "npm run migrate && npm start"]
```
</Accordion>
### Build and run your container
Build your image:
```bash
docker build -t orders-service .
```
On the machine where Docker runs, authenticate the machine identity and start the container using the commands for your Infisical deployment:
<CodeGroup>
```bash Infisical Cloud US
export INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id=<client-id> \
--client-secret=<client-secret> \
--plain \
--silent)
docker run --rm --env INFISICAL_TOKEN orders-service
```
```bash EU Cloud or self-hosted
# Use https://eu.infisical.com for EU Cloud or your self-hosted instance URL
export INFISICAL_DOMAIN=<your-infisical-domain>
export INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id=<client-id> \
--client-secret=<client-secret> \
--plain \
--silent)
docker run --rm --env INFISICAL_TOKEN --env INFISICAL_DOMAIN orders-service
```
</CodeGroup>
<Note>
If your self-hosted Infisical instance is running locally on the Docker host, don't set `INFISICAL_DOMAIN` to a `localhost` URL, since this will point to the container itself.
Instead, set it to a `host.docker.internal` URL, [which points to the container's host domain](https://docs.docker.com/desktop/features/networking/networking-how-tos/#connect-a-container-to-a-service-on-the-host).
</Note>
Replace `<client-id>` and `<client-secret>` with the machine identity credentials you created earlier. The access token is passed to the container at runtime and isn't stored in the image.
<Check>
Your application can now read secrets as environment variables when the container starts.
</Check>
Alternatively, you can run the Infisical CLI on the host and pass exported secrets to an existing image through Docker's `--env-file` option. This method doesn't require you to install the CLI in the image.
<Note>
This method requires a Bash-compatible shell because it uses process substitution.
</Note>
### Authenticate with the CLI
Authenticate with Infisical by running [`infisical login`](/cli/commands/login):
```bash
infisical login
```
This prompts you to select your hosting option, then opens your browser to complete the login.
### Connect your project
In your application's directory, link it to the project you created by running [`infisical init`](/cli/commands/init):
```bash
infisical init
```
Follow the prompts to select your organization and project.
### Run your container
Export the secrets from the **Development** environment and pass them to your container:
```bash
docker run --rm \
--env-file <(infisical export --env=dev --format=dotenv) \
orders-service
```
Replace `orders-service` with the image you want to run. Infisical serves the exported secrets through a temporary file descriptor rather than writing a `.env` file to disk.
<Warning>
Docker's `--env-file` option doesn't support multiline secret values. Use the startup method if your application requires multiline secrets.
</Warning>
<Check>
Your container can now read the exported secrets as environment variables.
</Check>
In CI/CD and other automated environments, use a [machine identity](/documentation/platform/identities/machine-identities) to authenticate the Infisical CLI on the host. The CLI exports your application secrets and passes them to an existing image through Docker's `--env-file` option.
<Note>
This method requires a Bash-compatible shell because it uses process substitution.
</Note>
### Configure machine identity access
Create a machine identity with permission to read the required secrets, configure it with [Universal Auth](/documentation/platform/identities/universal-auth), and copy its **Client ID** and **Client Secret**. Then copy the **Project ID** from **Project Settings**.
Store these values in your automation platform's secret store rather than in source control.
### Authenticate with the CLI
Exchange the machine identity credentials for a short-lived access token using the commands for your Infisical deployment:
<CodeGroup>
```bash Infisical Cloud US
export INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id=<client-id> \
--client-secret=<client-secret> \
--plain \
--silent)
```
```bash EU Cloud or self-hosted
# Use https://eu.infisical.com for EU Cloud or your self-hosted instance URL
export INFISICAL_DOMAIN=<your-infisical-domain>
export INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id=<client-id> \
--client-secret=<client-secret> \
--plain \
--silent)
```
</CodeGroup>
### Run your container
Identify the project explicitly when exporting secrets, then pass them to the container:
```bash
docker run --rm \
--env-file <(infisical export --projectId=<project-id> --env=dev --format=dotenv) \
orders-service
```
Replace `<project-id>` with your project ID and `orders-service` with the image you want to run.
<Warning>
Docker's `--env-file` option doesn't support multiline secret values. Use the startup method if your application requires multiline secrets.
</Warning>
<Check>
Your automation can now authenticate without a user session and inject secrets into the container.
</Check>
If you fetch secrets at startup, you can use Docker Compose to build and run one or more configured service images.
Configure each image to start through infisical run, then configure your Compose file for your Infisical deployment:
services:
orders-service:
build: .
environment:
INFISICAL_TOKEN: ${INFISICAL_TOKEN}
INFISICAL_DOMAIN: ${INFISICAL_DOMAIN}
Authenticate the machine identity in the same shell, then start the services using the commands for your Infisical deployment:
<CodeGroup> ```bash Infisical Cloud US export INFISICAL_TOKEN=$(infisical login \ --method=universal-auth \ --client-id=<client-id> \ --client-secret=<client-secret> \ --plain \ --silent)docker compose up --build
```bash EU Cloud or self-hosted
# Use https://eu.infisical.com for EU Cloud or your self-hosted instance URL
export INFISICAL_DOMAIN=<your-infisical-domain>
export INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id=<client-id> \
--client-secret=<client-secret> \
--plain \
--silent)
docker compose up --build
Instead, set it to a host.docker.internal URL, which points to the container's host domain.
</Note>
If multiple services need different access permissions, create a machine identity for each permission set and pass each access token through a separate variable.
Map each service to the access token for its machine identity:
<CodeGroup> ```yaml Infisical Cloud US services: web: build: ./web environment: INFISICAL_TOKEN: ${INFISICAL_TOKEN_WEB}api:
build: ./api
environment:
INFISICAL_TOKEN: ${INFISICAL_TOKEN_API}
```yaml EU Cloud or self-hosted
services:
web:
build: ./web
environment:
INFISICAL_TOKEN: ${INFISICAL_TOKEN_WEB}
INFISICAL_DOMAIN: ${INFISICAL_DOMAIN}
api:
build: ./api
environment:
INFISICAL_TOKEN: ${INFISICAL_TOKEN_API}
INFISICAL_DOMAIN: ${INFISICAL_DOMAIN}
Authenticate each identity before starting the services:
<CodeGroup> ```bash Infisical Cloud US export INFISICAL_TOKEN_WEB=$(infisical login \ --method=universal-auth \ --client-id=<web-client-id> \ --client-secret=<web-client-secret> \ --plain \ --silent)export INFISICAL_TOKEN_API=$(infisical login
--method=universal-auth
--client-id=<api-client-id>
--client-secret=<api-client-secret>
--plain
--silent)
docker compose up --build
```bash EU Cloud or self-hosted
# Use https://eu.infisical.com for EU Cloud or your self-hosted instance URL
export INFISICAL_DOMAIN=<your-infisical-domain>
export INFISICAL_TOKEN_WEB=$(infisical login \
--method=universal-auth \
--client-id=<web-client-id> \
--client-secret=<web-client-secret> \
--plain \
--silent)
export INFISICAL_TOKEN_API=$(infisical login \
--method=universal-auth \
--client-id=<api-client-id> \
--client-secret=<api-client-secret> \
--plain \
--silent)
docker compose up --build