{"id":4200,"date":"2026-08-10T17:52:19","date_gmt":"2026-08-10T09:52:19","guid":{"rendered":"https:\/\/www.yaoyingying.com\/?p=4200"},"modified":"2026-08-10T18:11:42","modified_gmt":"2026-08-10T10:11:42","slug":"infisical-and-docker-environment-variables","status":"publish","type":"post","link":"https:\/\/www.yaoyingying.com\/en\/blog\/2026\/08\/10\/infisical-and-docker-environment-variables\/","title":{"rendered":"Infisical and Docker Environment Variables"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This document describes how this project uses Infisical for secrets and override configuration alongside the existing Docker Compose workflow. Goal: <code>.env<\/code><strong> holds orchestration and non-secret defaults; <\/strong><code>.env.local<\/code><strong> is exported from Infisical at startup and injected into the WordPress container<\/strong>. Infisical project, environment, and connection settings are provided entirely via environment variables.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Related files:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>start<\/code>: logs in with <code>infisical\/cli<\/code> before startup and exports <code>.env.local<\/code><\/li>\n\n\n\n<li><code>docker-compose.yml<\/code>: <code>wordpress_frankenphp<\/code> loads both <code>.env<\/code> and <code>.env.local<\/code><\/li>\n\n\n\n<li><code>.env.default<\/code>: commit-safe local default env template<\/li>\n\n\n\n<li><code>.env.infisical.example<\/code>: commit-safe Infisical connection template; copy to <code>.env.infisical<\/code> and fill in real values<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Self-hosted example: <code>https:\/\/secret-manager.it-consultis.net<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Infisical environment variables<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Variable<\/th><th>Purpose<\/th><\/tr><tr><td><code>INFISICAL_DOMAIN<\/code><\/td><td>Self-hosted or Cloud API URL<\/td><\/tr><tr><td><code>INFISICAL_ORGANIZATION_ID<\/code><\/td><td>Organization ID used at login<\/td><\/tr><tr><td><code>INFISICAL_PROJECT_ID<\/code><\/td><td>Infisical Project ID passed to <code>--projectId<\/code> for export \/ run<\/td><\/tr><tr><td><code>INFISICAL_ENV<\/code><\/td><td>Infisical Environment slug, e.g. <code>local<\/code>, <code>production-us<\/code><\/td><\/tr><tr><td><code>INFISICAL_EMAIL<\/code> \/ <code>INFISICAL_PASSWORD<\/code><\/td><td>Local personal login (do not commit)<\/td><\/tr><tr><td><code>INFISICAL_CLIENT_ID<\/code> \/ <code>INFISICAL_CLIENT_SECRET<\/code><\/td><td>Machine Identity (recommended for CI \/ servers)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Variable layering<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Kind<\/th><th>Examples<\/th><th>Where to store<\/th><\/tr><tr><td>Compose orchestration<\/td><td><code>COMPOSE_PROJECT_NAME<\/code>, <code>WORDPRESS_HTTP_PORT<\/code>, <code>VERSION<\/code>, <code>CONTAINER_REGISTRY<\/code>, <code>DOCKER_NETWORK_*<\/code><\/td><td><code>.env<\/code> (generated from <code>.env.default<\/code>)<\/td><\/tr><tr><td>Environment-specific config<\/td><td><code>ENVIRONMENT<\/code>, <code>WORDPRESS_SITE_URL<\/code>, DB host<\/td><td>May stay in <code>.env<\/code>; migrate to Infisical over time<\/td><\/tr><tr><td>Secrets \/ sensitive overrides<\/td><td><code>WORDPRESS_*_KEY<\/code>, <code>WORDPRESS_*_SALT<\/code>, <code>JWT_AUTH_SECRET_KEY<\/code>, DB password, admin password, etc.<\/td><td>Infisical \u2192 exported as <code>.env.local<\/code><\/td><\/tr><tr><td>Infisical connection &amp; auth<\/td><td>Domain, Organization ID, Project ID, <code>INFISICAL_ENV<\/code>, login credentials<\/td><td><strong>Local<\/strong> <code>.env.infisical<\/code> (do not commit)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Do not put Infisical personal email\/password or Machine Identity client secrets in <code>start<\/code> or any committed file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">File conventions<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>.env                    # Local orchestration and defaults (gitignore)\n.env.default            # Commit-safe template; copied to .env on first start\n.env.local              # Infisical export output (gitignore)\n.env.infisical          # Infisical connection\/auth (gitignore)\n.env.infisical.example  # Commit-safe template without real passwords<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ensure <code>.gitignore<\/code> includes at least:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.env\n.env.local\n.env.infisical<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Startup flow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Order of operations in <code>.\/start<\/code>:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>If <code>.env<\/code> is missing, copy it from <code>.env.default<\/code>.<\/li>\n\n\n\n<li>Load Infisical connection settings from <code>.env.infisical<\/code> (or already-exported environment variables).<\/li>\n\n\n\n<li>Log in with the <code>infisical\/cli<\/code> image and obtain a short-lived <code>INFISICAL_TOKEN<\/code>.<\/li>\n\n\n\n<li>Run <code>infisical export --projectId=... --env=...<\/code> and write <code>.env.local<\/code>.<\/li>\n\n\n\n<li><code>source .env<\/code>, create the network if needed, and run <code>.\/docker-compose up<\/code>.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Example WordPress service in <code>docker-compose.yml<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  wordpress_frankenphp:\n    env_file:\n      - path: .\/.env\n        required: true\n      - path: .\/.env.local\n        required: false<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Later <code>env_file<\/code> entries override earlier ones with the same key (this applies to <strong>service <\/strong><code>env_file<\/code><strong> merge only<\/strong>).<\/li>\n\n\n\n<li><code>required: false<\/code>: if export fails or Infisical is not configured locally, the stack can still start from <code>.env<\/code> alone (depending on whether the app needs those secrets).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Local auth file example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Copy the template and fill in values:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp .env.infisical.example .env.infisical<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example <code>.env.infisical<\/code> contents:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>INFISICAL_DOMAIN=https:\/\/secret-manager.it-consultis.net\nINFISICAL_ORGANIZATION_ID=&lt;organization-id&gt;\nINFISICAL_PROJECT_ID=&lt;project-id&gt;\nINFISICAL_ENV=local\n\n# Personal login on a developer machine only\nINFISICAL_EMAIL=&lt;your-email&gt;\nINFISICAL_PASSWORD=&lt;your-password&gt;\n\n# Or use Machine Identity (recommended for CI \/ shared servers)\n# INFISICAL_CLIENT_ID=&lt;client-id&gt;\n# INFISICAL_CLIENT_SECRET=&lt;client-secret&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Suggested pattern in <code>start<\/code> \u2014 load the file, then call the CLI:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if &#91; -f .env.infisical ]; then\n  # shellcheck disable=SC1091\n  source .env.infisical\nfi\n\n: \"${INFISICAL_DOMAIN:?INFISICAL_DOMAIN is required}\"\n: \"${INFISICAL_PROJECT_ID:?INFISICAL_PROJECT_ID is required}\"\n: \"${INFISICAL_ORGANIZATION_ID:?INFISICAL_ORGANIZATION_ID is required}\"\n\nexport INFISICAL_TOKEN=$(docker run --rm infisical\/cli login \\\n  --domain \"${INFISICAL_DOMAIN}\" \\\n  --email \"${INFISICAL_EMAIL}\" \\\n  --password \"${INFISICAL_PASSWORD}\" \\\n  --organization-id \"${INFISICAL_ORGANIZATION_ID}\" \\\n  --plain \\\n  --silent)\n\ndocker run --rm infisical\/cli export \\\n  --domain \"${INFISICAL_DOMAIN}\" \\\n  --env=\"${INFISICAL_ENV:-local}\" \\\n  --projectId=\"${INFISICAL_PROJECT_ID}\" \\\n  --token=\"${INFISICAL_TOKEN}\" &gt; .env.local<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For multiple environments, select the Infisical environment with <code>INFISICAL_ENV<\/code> (optionally mapped from <code>ENVIRONMENT<\/code>), e.g. <code>local<\/code>, <code>develop-us<\/code>, <code>production-eu<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Machine Identity (CI \/ servers)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>export INFISICAL_TOKEN=$(docker run --rm infisical\/cli login \\\n  --domain \"${INFISICAL_DOMAIN}\" \\\n  --method=universal-auth \\\n  --client-id \"${INFISICAL_CLIENT_ID}\" \\\n  --client-secret \"${INFISICAL_CLIENT_SECRET}\" \\\n  --plain \\\n  --silent)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Store credentials in the deployment platform or private server config \u2014 never in Git.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Compose interpolation vs override order (important)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Docker Compose has two separate environment-variable mechanisms:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Project-level <\/strong><code>.env<\/code><strong> (or <\/strong><code>--env-file<\/code><strong>)<\/strong>: used for <code>${VAR}<\/code> interpolation in Compose files (image names, ports, network names, etc.).<\/li>\n\n\n\n<li><strong>Service <\/strong><code>env_file<\/code>: injected into the container process environment.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Also note: if a service defines <code>environment:<\/code>, those values <strong>override<\/strong> same-named keys from <code>env_file<\/code>. Interpolation such as <code>${WORDPRESS_DB_PASSWORD:-root}<\/code> only reads the project-level <code>.env<\/code> and <strong>does not<\/strong> automatically read <code>.env.local<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Do not also declare secrets that live only in <code>.env.local<\/code> under <code>environment:<\/code> with <code>${...}<\/code>, or project <code>.env<\/code> defaults will win.<\/li>\n\n\n\n<li>Keep Compose orchestration variables in <code>.env<\/code>.<\/li>\n\n\n\n<li>Put secrets and runtime overrides in Infisical \u2192 <code>.env.local<\/code>, and inject them via <code>env_file<\/code> rather than duplicating them in <code>environment:<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Recommended container-side precedence:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.env (defaults) \u2192 .env.local (Infisical overrides) \u2192 environment: (non-secret, intentionally hard-coded items only)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Infisical project setup<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create a Project in Infisical for this repo and set <code>INFISICAL_PROJECT_ID<\/code> locally.<\/li>\n\n\n\n<li>Create Environments aligned with existing <code>ENVIRONMENT<\/code> values when possible (e.g. <code>local<\/code>, <code>uat-us<\/code>, <code>production-eu<\/code>), and set <code>INFISICAL_ENV<\/code> accordingly.<\/li>\n\n\n\n<li>Import secrets and environment-specific overrides into each Environment.<\/li>\n\n\n\n<li>Local development: personal account or a dev Machine Identity with read access to <code>local<\/code> only.<\/li>\n\n\n\n<li>CI \/ regional servers: separate Machine Identities with least privilege, read-only on the matching Environment.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Over time, <code>sed<\/code>-based edits in <code>deploy\/scripts\/modify-dot-env-*.sh<\/code> for secrets and regional differences can be replaced by per-environment <code>infisical export<\/code>, reducing long-lived hand-edited <code>.env<\/code> files on disk.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Day-to-day usage<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># 1. Prepare .env (first time)\ncp .env.default .env   # or let .\/start copy it\n\n# 2. Prepare Infisical connection settings (first time)\ncp .env.infisical.example .env.infisical\n# Edit .env.infisical: Project ID, Organization ID, login credentials, etc.\n\n# 3. Maintain secrets in the matching Infisical environment\n\n# 4. Start (refreshes .env.local and brings containers up)\n.\/start -d<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the container received Infisical variables:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.\/docker-compose exec wordpress_frankenphp env | grep -E 'INFISICAL_TEST|WP_REDIS_PREFIX|JWT_AUTH'<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Security notes<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Do not commit Infisical passwords, client secrets, or a full <code>.env.local<\/code> to Git, and do not bake them into images.<\/li>\n\n\n\n<li>If credentials were ever written into <code>start<\/code> or chat logs, rotate the password or revoke the client secret in Infisical immediately.<\/li>\n\n\n\n<li><code>INFISICAL_TOKEN<\/code> is short-lived and only for that export run; do not persist it in image layers.<\/li>\n\n\n\n<li>Prefer Machine Identity in production so personal account passwords never appear in server scripts.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Optional later evolution<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The current approach (host-side export \u2192 <code>.env.local<\/code> \u2192 <code>env_file<\/code>) is low-churn and fits a gradual migration from existing deploy scripts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To reduce secrets written to disk on servers later:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install the Infisical CLI in the image;<\/li>\n\n\n\n<li>Wrap the container <code>CMD<\/code> with <code>infisical run --projectId=... --env=... -- ... \/start<\/code>;<\/li>\n\n\n\n<li>Pass only <code>INFISICAL_TOKEN<\/code> (and <code>INFISICAL_DOMAIN<\/code> for self-hosted) via Compose.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A thin orchestration <code>.env<\/code> is still required, because Compose resolves <code>${...}<\/code> before the container fetches secrets at startup.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Related docs<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/infisical.com\/docs\/integrations\/platforms\/docker\">Infisical Docker integration<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/infisical.com\/docs\/integrations\/platforms\/docker-compose\">Infisical Docker Compose<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This document describes how this project uses Infisical for secrets and override configuration alongside the existing Docker Compose workflow. Goal: .env holds orchestration and non-secret defaults; .env.local is exported from &#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[894],"tags":[],"class_list":["post-4200","post","type-post","status-publish","format-standard","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/posts\/4200","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/comments?post=4200"}],"version-history":[{"count":1,"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/posts\/4200\/revisions"}],"predecessor-version":[{"id":4201,"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/posts\/4200\/revisions\/4201"}],"wp:attachment":[{"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/media?parent=4200"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/categories?post=4200"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.yaoyingying.com\/en\/wp-json\/wp\/v2\/tags?post=4200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}