{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "stitch-docker", "title": "Stitch Docker Configuration", "description": "Generic Bun multi-stage container and nginx configuration for a Vite single-page application.", "files": [ { "path": "registry/scaffolds/docker/Dockerfile", "content": "# syntax=docker/dockerfile:1\n\nFROM oven/bun:1 AS dependencies\nWORKDIR /app\n\nCOPY package.json bun.lock ./\nRUN bun install --frozen-lockfile\n\nFROM dependencies AS build\nWORKDIR /app\n\nCOPY . .\n\n# VITE_* values are public client configuration compiled into the bundle at\n# build time. Generate the file with scripts/generate-env.sh and pass its path as\n# ENV_FILE. The destination name matters: Vite only auto-loads .env.production\n# for the production-mode build that `bun run build` runs.\nARG ENV_FILE\nCOPY ${ENV_FILE} .env.production\n\nRUN bun run build\n\nFROM nginx:1.29-alpine AS runtime\n\nRUN chown -R nginx:nginx /var/cache/nginx /run\n\nCOPY --chown=nginx:nginx --from=build /app/dist /usr/share/nginx/html\nCOPY --chown=nginx:nginx nginx.conf /etc/nginx/conf.d/default.conf\n\nUSER nginx\n\nEXPOSE 8080\n\nHEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\\n CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:8080/healthz || exit 1\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n", "type": "registry:file", "target": "~/Dockerfile" }, { "path": "registry/scaffolds/docker/nginx.conf", "content": "server {\n listen 8080;\n listen [::]:8080;\n server_name _;\n\n root /usr/share/nginx/html;\n index index.html;\n\n location = /healthz {\n access_log off;\n default_type text/plain;\n return 200 \"ok\\n\";\n }\n\n location /assets/ {\n try_files $uri =404;\n expires 1y;\n add_header Cache-Control \"public, max-age=31536000, immutable\";\n }\n\n location = /index.html {\n try_files $uri =404;\n add_header Cache-Control \"no-cache, no-store, must-revalidate\";\n }\n\n location / {\n try_files $uri $uri/ /index.html;\n add_header Cache-Control \"no-cache\";\n }\n}\n", "type": "registry:file", "target": "~/nginx.conf" }, { "path": "registry/scaffolds/docker/.dockerignore", "content": ".git\n.gitignore\n.DS_Store\n\n# Local env files only. The generated .env.- that ENV_FILE points\n# at must stay in the build context, so this cannot be a blanket .env* ignore.\n.env\n.env.local\n.env.*.local\n\n.vercel\ncoverage\ndist\nnode_modules\nnpm-debug.log*\npnpm-debug.log*\nyarn-error.log*\n", "type": "registry:file", "target": "~/.dockerignore" }, { "path": "registry/scaffolds/docker/generate-env.sh", "content": "#!/usr/bin/env bash\n\nset -e\n\nPROJECT_NAME=$1\nENV_NAME=$2\nCOMPONENT_NAME=${3:-frontend}\nAWS_REGION=${AWS_REGION:-us-east-2}\n\nif [ -z \"$PROJECT_NAME\" ] || [ -z \"$ENV_NAME\" ]; then\n echo \"Usage: ./generate-env.sh [component_name]\"\n exit 1\nfi\n\nAWS_PROFILE=\"${AWS_PROFILE:-${PROJECT_NAME}-${ENV_NAME}}\"\nSECRET_ID=\"${PROJECT_NAME}/${ENV_NAME}/${COMPONENT_NAME}\"\nENV_FILE=\".env.${PROJECT_NAME}-${ENV_NAME}\"\n\necho \"--------------------------------------------\"\necho \"Project : $PROJECT_NAME\"\necho \"Environment : $ENV_NAME\"\necho \"AWS Profile : $AWS_PROFILE\"\necho \"AWS Region : $AWS_REGION\"\necho \"Secret ID : $SECRET_ID\"\necho \"Env File : $ENV_FILE\"\necho \"--------------------------------------------\"\n\n# If file already exists, skip fetching (developer override support)\nif [ -f \"$ENV_FILE\" ]; then\n echo \"Env file $ENV_FILE already exists. Skipping secret fetch.\"\n exit 0\nfi\n\necho \"Fetching secrets from AWS Secrets Manager...\"\n\n# Detect if AWS credentials are already available (CI / OIDC / env-based auth)\nif aws sts get-caller-identity >/dev/null 2>&1; then\n echo \"Using existing AWS environment credentials\"\n PROFILE_ARG=\"\"\nelse\n echo \"No environment credentials detected. Using profile: $AWS_PROFILE\"\n PROFILE_ARG=\"--profile $AWS_PROFILE\"\nfi\n\nSECRET_JSON=$(aws secretsmanager get-secret-value \\\n $PROFILE_ARG \\\n --region \"$AWS_REGION\" \\\n --secret-id \"$SECRET_ID\" \\\n --query SecretString \\\n --output text)\n\nif [ -z \"$SECRET_JSON\" ]; then\n echo \"Failed to fetch secret or secret is empty.\"\n exit 1\nfi\n\necho \"Converting secret JSON to env format...\"\n\necho \"$SECRET_JSON\" | jq -r 'to_entries | .[] | \"\\(.key)=\\(.value)\"' > \"$ENV_FILE\"\n\necho \"Env file generated successfully: $ENV_FILE\"\n", "type": "registry:file", "target": "~/scripts/generate-env.sh" } ], "docs": "VITE_* variables are public client configuration compiled into the bundle during the image build; runtime environment changes do not rewrite the built bundle. Build them in with an env file rather than one build argument per value: run `chmod +x scripts/generate-env.sh && ./scripts/generate-env.sh [component]` to write .env.- from AWS Secrets Manager, then build with `--build-arg ENV_FILE=.env.-`. ENV_FILE has no default and the build fails without it. The script reuses an existing env file, so hand-write one to build without AWS access. Keep .env out of the build context: Vite loads it in every mode, so a developer copy would backfill any key the secret omits.", "type": "registry:item" }