mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 11:44:31 +00:00
feat: add export-assets script for CDN asset extraction and update Dockerfiles
This commit is contained in:
@@ -185,6 +185,9 @@ COPY --from=backend-runner /app /backend
|
||||
|
||||
COPY --from=frontend-runner /app ./backend/frontend-build
|
||||
|
||||
# Make export-assets script executable for CDN asset extraction
|
||||
RUN chmod +x /backend/scripts/export-assets.sh
|
||||
|
||||
ARG INFISICAL_PLATFORM_VERSION
|
||||
ENV INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
|
||||
|
||||
|
||||
@@ -174,6 +174,9 @@ ENV CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY
|
||||
COPY --from=backend-runner /app /backend
|
||||
COPY --from=frontend-runner /app ./backend/frontend-build
|
||||
|
||||
# Make export-assets script executable for CDN asset extraction
|
||||
RUN chmod +x /backend/scripts/export-assets.sh
|
||||
|
||||
ARG INFISICAL_PLATFORM_VERSION
|
||||
ENV INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"outputPath": "binary"
|
||||
},
|
||||
"scripts": {
|
||||
"assets:export": "./scripts/export-assets.sh",
|
||||
"binary:build": "npm run binary:clean && npm run build:frontend && npm run build && npm run binary:babel-frontend && npm run binary:babel-backend && npm run binary:rename-imports",
|
||||
"binary:package": "pkg --no-bytecode --public-packages \"*\" --public --target host .",
|
||||
"binary:babel-backend": " babel ./dist -d ./dist",
|
||||
|
||||
77
backend/scripts/export-assets.sh
Normal file
77
backend/scripts/export-assets.sh
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/bin/sh
|
||||
# Export frontend static assets for CDN deployment
|
||||
# Usage:
|
||||
# npm run assets:export - Output tar to stdout (pipe to file or aws s3)
|
||||
# npm run assets:export /path - Extract assets to specified directory
|
||||
# npm run assets:export -- --help - Show usage
|
||||
|
||||
set -e
|
||||
|
||||
ASSETS_PATH="/backend/frontend-build/assets"
|
||||
|
||||
show_help() {
|
||||
cat << 'EOF'
|
||||
Export frontend static assets for CDN deployment.
|
||||
|
||||
USAGE:
|
||||
docker run --rm infisical/infisical npm run assets:export [-- OPTIONS] [PATH]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h Show this help message
|
||||
|
||||
ARGUMENTS:
|
||||
PATH Directory to export assets to. If not provided, outputs
|
||||
a tar archive to stdout.
|
||||
|
||||
EXAMPLES:
|
||||
# Export as tar to local file
|
||||
docker run --rm infisical/infisical npm run assets:export > assets.tar
|
||||
|
||||
# Extract to local directory
|
||||
docker run --rm -v $(pwd)/cdn-assets:/output infisical/infisical npm run assets:export /output
|
||||
|
||||
# Pipe directly to S3 (using aws cli on host)
|
||||
docker run --rm infisical/infisical npm run assets:export | \
|
||||
tar -xf - -C ./tmp-assets && \
|
||||
aws s3 sync ./tmp-assets s3://my-bucket/assets
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Check for help flag
|
||||
case "${1:-}" in
|
||||
--help|-h)
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
|
||||
# Verify assets exist
|
||||
if [ ! -d "$ASSETS_PATH" ]; then
|
||||
echo "Error: Assets directory not found at $ASSETS_PATH" >&2
|
||||
echo "Make sure the frontend is built and included in the image." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ASSET_COUNT=$(find "$ASSETS_PATH" -type f | wc -l | tr -d ' ')
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
# No path provided - output tar to stdout
|
||||
echo "Exporting $ASSET_COUNT assets as tar archive to stdout..." >&2
|
||||
tar -cf - -C "$(dirname "$ASSETS_PATH")" "$(basename "$ASSETS_PATH")"
|
||||
else
|
||||
# Path provided - extract to directory
|
||||
OUTPUT_PATH="$1"
|
||||
|
||||
if [ ! -d "$OUTPUT_PATH" ]; then
|
||||
echo "Creating output directory: $OUTPUT_PATH" >&2
|
||||
mkdir -p "$OUTPUT_PATH"
|
||||
fi
|
||||
|
||||
echo "Exporting $ASSET_COUNT assets to $OUTPUT_PATH..." >&2
|
||||
cp -r "$ASSETS_PATH"/* "$OUTPUT_PATH/"
|
||||
|
||||
echo "✅ Assets exported successfully!" >&2
|
||||
echo " Path: $OUTPUT_PATH" >&2
|
||||
echo " Files: $ASSET_COUNT assets" >&2
|
||||
fi
|
||||
@@ -330,6 +330,7 @@
|
||||
"self-hosting/guides/custom-certificates",
|
||||
"self-hosting/guides/automated-bootstrapping",
|
||||
"self-hosting/guides/production-hardening",
|
||||
"self-hosting/guides/cdn-caching",
|
||||
"self-hosting/guides/monitoring-telemetry"
|
||||
]
|
||||
},
|
||||
|
||||
106
docs/self-hosting/guides/cdn-caching.mdx
Normal file
106
docs/self-hosting/guides/cdn-caching.mdx
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: "CDN Caching for Static Assets"
|
||||
description: "How to set up CDN caching to prevent version skew issues during deployments"
|
||||
---
|
||||
|
||||
This guide explains a common issue with frontend asset caching during deployments and how to solve it using a CDN.
|
||||
|
||||
## The Problem: Version Skew
|
||||
|
||||
Modern frontend build tools like Vite generate content-hashed filenames for static assets (e.g., `main-abc123.js`). Each build produces unique filenames based on file contents. During deployments, this can cause a race condition:
|
||||
|
||||
1. User loads `index.html` which references `main-abc123.js`
|
||||
2. New deployment replaces containers with a new build
|
||||
3. New containers only serve `main-xyz789.js` (new build)
|
||||
4. User's browser requests `main-abc123.js` from cached HTML
|
||||
5. Request returns **404** — the old asset no longer exists
|
||||
|
||||
This results in broken pages, failed SPA navigation, and requires users to manually refresh.
|
||||
|
||||
<Note>
|
||||
This is a documented limitation in Vite's official guidance: [Load Error Handling](https://vite.dev/guide/build#load-error-handling)
|
||||
</Note>
|
||||
|
||||
### Current Behavior
|
||||
|
||||
Infisical includes a built-in workaround that detects version mismatches and triggers a page reload. While functional, this introduces a noticeable delay for users during deployments.
|
||||
|
||||
## The Solution: External Asset Storage
|
||||
|
||||
The solution is to store static assets externally (e.g., S3, GCS, Azure Blob) and serve them through a CDN (e.g., CloudFront, Cloud CDN, Cloudflare). Assets are uploaded **before** container deployment, ensuring old versions remain available.
|
||||
|
||||
### How It Works
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User[User Browser]
|
||||
CDN[CDN]
|
||||
S3[(Object Storage)]
|
||||
App[Your Infrastructure]
|
||||
|
||||
User --> CDN
|
||||
CDN -->|"/assets/*"| S3
|
||||
CDN -->|"/* (default)"| App
|
||||
```
|
||||
|
||||
The key points:
|
||||
|
||||
- **Asset persistence**: Old assets remain available even after new deployments
|
||||
- **Deployment order**: Upload new assets before deploying new containers
|
||||
- **Long cache TTL**: Content-hashed files can be cached indefinitely (we recommend 30 days)
|
||||
- **Automatic cleanup**: Configure lifecycle rules to expire old assets after 30 days
|
||||
|
||||
At Infisical, we use **CloudFront + S3** for this purpose, but you can use any CDN and object storage combination that fits your infrastructure.
|
||||
|
||||
## Exporting Assets
|
||||
|
||||
Infisical provides a built-in command to export frontend assets from the Docker image:
|
||||
|
||||
```bash
|
||||
# Export as tar archive to stdout
|
||||
docker run --rm infisical/infisical npm run assets:export > assets.tar
|
||||
|
||||
# Extract the archive
|
||||
tar -xf assets.tar
|
||||
ls assets/ # Content-hashed JS/CSS files
|
||||
```
|
||||
|
||||
Or export directly to a mounted directory:
|
||||
|
||||
```bash
|
||||
docker run --rm -v $(pwd)/cdn-assets:/output \
|
||||
infisical/infisical npm run assets:export /output
|
||||
```
|
||||
|
||||
### What Gets Exported
|
||||
|
||||
The command exports the `/assets` directory containing:
|
||||
|
||||
- JavaScript bundles (e.g., `main-abc123.js`, `chunk-def456.js`)
|
||||
- CSS files (e.g., `styles-789xyz.css`)
|
||||
- Other static assets with content hashes
|
||||
|
||||
These files are safe to cache with long TTLs because their filenames change whenever the content changes.
|
||||
|
||||
## Integration with Your Pipeline
|
||||
|
||||
The general deployment flow should be:
|
||||
|
||||
1. **Build** your new Docker image (or pull the official Infisical image)
|
||||
2. **Export** assets using `npm run assets:export`
|
||||
3. **Upload** assets to your object storage
|
||||
4. **Deploy** the new container version
|
||||
|
||||
```bash
|
||||
# Example: Export and upload to S3
|
||||
docker run --rm infisical/infisical:$VERSION npm run assets:export > assets.tar
|
||||
tar -xf assets.tar
|
||||
aws s3 sync assets s3://your-bucket/assets --cache-control "public, max-age=2592000"
|
||||
|
||||
# Then deploy your container
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Always upload assets **before** deploying the new container. This ensures the assets referenced by the new `index.html` exist before users can access them.
|
||||
</Warning>
|
||||
|
||||
Reference in New Issue
Block a user