Keep the personal half of the desktop in one place, and ask before installing it

Agent instructions, skills, SSH host aliases and expansion triggers are worth
having identical on every machine one person owns, and belong in none of the
shared configuration. They live in user/ now, with a manifest saying where each
piece goes and a link-user stage that puts it there.

That stage does nothing unless the machine said yes. Somebody who clones Panama
to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was;
the question names the destinations and defaults to no. Anything displaced goes
to config/old rather than being deleted.

~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one
file, which is the drift this exists to prevent.

Also adds the vitals toggles for the battery and Claude usage readouts, which
had preferences and no way to reach them.
This commit is contained in:
Gabriel Brown
2026-08-22 08:54:43 -04:00
parent 8b96d907a1
commit 89761a7da3
156 changed files with 16439 additions and 6 deletions
@@ -0,0 +1,405 @@
# Docker Deployment Guide
Deploy Infisical using Docker or Docker Compose for flexible, containerized self-hosted environments.
## Docker Standalone Container
### Quick Start
1. Pull the image:
```bash
docker pull infisical/infisical:latest
```
2. Create a `.env` file with required configuration:
```bash
ENCRYPTION_KEY=$(openssl rand -hex 16)
AUTH_SECRET=$(openssl rand -base64 32)
DB_CONNECTION_URI="postgresql://user:[email protected]:5432/infisical"
REDIS_URL="redis://redis.example.com:6379"
SITE_URL="https://secrets.example.com"
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USERNAME="[email protected]"
SMTP_PASSWORD="password"
SMTP_FROM_ADDRESS="[email protected]"
```
3. Run the container:
```bash
docker run -d \
--name infisical \
--env-file .env \
-p 8080:8080 \
infisical/infisical:latest
```
4. Verify the container is running:
```bash
curl http://localhost:8080/api/status
```
### Image Variants
#### Standard Image
```bash
docker pull infisical/infisical:latest
docker pull infisical/infisical:v0.110.0 # Specific version
```
#### FIPS 140-2 Compliant Image
Use the FIPS image for regulated environments requiring FIPS compliance:
```bash
docker pull infisical/infisical:latest-fips
```
When using the FIPS image, set:
```bash
FIPS_ENABLED=true
NODE_OPTIONS="--max-old-space-size=8192 --force-fips"
```
## Docker Compose Deployment (Production)
The repository includes `docker-compose.prod.yml` for complete production setups with PostgreSQL and Redis.
### Basic docker-compose.yml
Create a `docker-compose.yml` file:
```yaml
version: '3.8'
services:
postgres:
image: postgres:14-alpine
container_name: infisical-postgres
environment:
POSTGRES_USER: infisical
POSTGRES_PASSWORD: infisical_db_password
POSTGRES_DB: infisical
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- infisical-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U infisical"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: infisical-redis
volumes:
- redis_data:/data
networks:
- infisical-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
infisical:
image: infisical/infisical:latest
container_name: infisical-api
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
AUTH_SECRET: ${AUTH_SECRET}
DB_CONNECTION_URI: postgresql://infisical:infisical_db_password@postgres:5432/infisical
REDIS_URL: redis://redis:6379
SITE_URL: https://secrets.example.com
SMTP_HOST: ${SMTP_HOST}
SMTP_PORT: ${SMTP_PORT}
SMTP_USERNAME: ${SMTP_USERNAME}
SMTP_PASSWORD: ${SMTP_PASSWORD}
SMTP_FROM_ADDRESS: ${SMTP_FROM_ADDRESS}
ports:
- "80:8080"
networks:
- infisical-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/status"]
interval: 30s
timeout: 10s
retries: 3
volumes:
postgres_data:
redis_data:
networks:
infisical-network:
driver: bridge
```
### Configuration
Create a `.env` file in the same directory:
```bash
# Generated keys
ENCRYPTION_KEY=a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8
AUTH_SECRET=VUJrQV9FbmNyeXB0aW9uS2V5XzMyQnl0ZXNfQmFzZTY0RW5jb2RlZA==
# SMTP Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=[email protected]
SMTP_PASSWORD=your-app-password
SMTP_FROM_ADDRESS=[email protected]
```
### Start the Services
```bash
docker-compose up -d
```
Monitor logs:
```bash
docker-compose logs -f infisical
```
### Upgrade
1. Backup the PostgreSQL database:
```bash
docker-compose exec postgres pg_dump -U infisical infisical > backup.sql
```
2. Pull the new image:
```bash
docker pull infisical/infisical:latest
```
3. Restart the services:
```bash
docker-compose down
docker-compose up -d
```
Schema migrations run automatically on startup.
## External Databases
If using managed PostgreSQL (RDS, Cloud SQL, Azure Database) or managed Redis (ElastiCache, Cloud Memorystore, Azure Cache), configure the connection URIs directly:
```yaml
environment:
DB_CONNECTION_URI: postgresql://user:[email protected]:5432/infisical
DB_ROOT_CERT: ${DB_ROOT_CERT} # Set if TLS certificate verification is required
REDIS_URL: rediss://redis-instance.cache.amazonaws.com:6380 # TLS enabled
```
For TLS certificates, base64-encode and pass as `DB_ROOT_CERT`:
```bash
cat /path/to/ca.pem | base64 -w 0 > /tmp/cert.b64
export DB_ROOT_CERT=$(cat /tmp/cert.b64)
```
## Production Hardening
### Read-Only Root Filesystem
Run the container with a read-only root filesystem and temporary writable mounts:
```yaml
infisical:
image: infisical/infisical:latest
read_only: true
tmpfs:
- /tmp
- /app/node_modules/.cache
```
This limits the attack surface if the container is compromised.
### Drop Capabilities
Drop unnecessary Linux capabilities:
```yaml
infisical:
image: infisical/infisical:latest
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
```
### Resource Limits
Set memory and CPU limits:
```yaml
infisical:
image: infisical/infisical:latest
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
```
Adjust based on your expected load.
### Network Security
Restrict network access:
```yaml
networks:
infisical-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-infisical
```
Use separate networks for different components (application, database, cache).
## Health Checks
The Infisical container exposes a health check endpoint:
```
GET /api/status
```
This returns HTTP 200 if the service is healthy.
### Docker Compose Health Check Configuration
```yaml
infisical:
image: infisical/infisical:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/status"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
```
## Logging
### JSON Logging
Logs are output as JSON for better integration with log aggregation systems:
```bash
docker-compose logs infisical | jq '.msg'
```
### Log File Output
Mount a volume to persist logs:
```yaml
infisical:
image: infisical/infisical:latest
volumes:
- ./logs:/app/logs
environment:
LOG_DIR: /app/logs
```
## Networking
### Reverse Proxy (Nginx)
Use Nginx to reverse proxy traffic to Infisical:
```nginx
upstream infisical {
server infisical:8080;
}
server {
listen 443 ssl http2;
server_name secrets.example.com;
ssl_certificate /etc/letsencrypt/live/secrets.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/secrets.example.com/privkey.pem;
location / {
proxy_pass http://infisical;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
In your `.env`, set:
```bash
SITE_URL=https://secrets.example.com
```
### Load Balancing
Deploy multiple Infisical containers behind a load balancer:
```yaml
infisical-1:
image: infisical/infisical:latest
environment:
DB_CONNECTION_URI: postgresql://...
REDIS_URL: redis://...
infisical-2:
image: infisical/infisical:latest
environment:
DB_CONNECTION_URI: postgresql://...
REDIS_URL: redis://...
infisical-3:
image: infisical/infisical:latest
environment:
DB_CONNECTION_URI: postgresql://...
REDIS_URL: redis://...
loadbalancer:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
```
All instances share the same PostgreSQL and Redis, making the service stateless and scalable.
## Backup and Recovery
### Backup PostgreSQL
```bash
docker-compose exec postgres pg_dump -U infisical infisical > backup_$(date +%s).sql
```
### Restore PostgreSQL
```bash
docker-compose exec -T postgres psql -U infisical infisical < backup.sql
```
### Backup Redis
```bash
docker-compose exec redis redis-cli BGSAVE
docker cp infisical-redis:/data/dump.rdb ./redis_backup.rdb
```
Always backup before upgrading or making configuration changes.
@@ -0,0 +1,294 @@
# Environment Variables Reference
This guide covers all environment variables used to configure Infisical self-hosted deployments.
## Essential Security Keys
### ENCRYPTION_KEY
**Required** Master encryption key for all secrets at rest.
- **Format**: 16 bytes as hex (32 hex characters)
- **Example**: `a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8`
- **Generation**: `openssl rand -hex 16`
- **Critical Notes**:
- Cannot be recovered if lost
- Must be stable across deployments and upgrades
- Rotate using Infisical's key rotation procedures (enterprise feature)
- Back up securely in a separate location
### AUTH_SECRET
**Required** Secret key for signing session tokens and JWTs.
- **Format**: 32 bytes as base64
- **Example**: `VUJrQV9FbmNyeXB0aW9uS2V5XzMyQnl0ZXNfQmFzZTY0RW5jb2RlZA==`
- **Generation**: `openssl rand -base64 32`
- **Notes**:
- Used for all authentication tokens
- Must be stable and unique per deployment
## Database Configuration
### DB_CONNECTION_URI
**Required** PostgreSQL connection string.
- **Format**: `postgresql://user:password@host:port/database`
- **Example**: `postgresql://infisical:[email protected]:5432/infisical`
- **Requirements**:
- PostgreSQL 14 or newer
- `uuid-ossp` extension enabled: `CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`
- `pgcrypto` extension enabled: `CREATE EXTENSION IF NOT EXISTS pgcrypto;`
### DB_ROOT_CERT
Optional Base64-encoded PEM certificate for SSL/TLS verification of PostgreSQL.
- **Format**: Base64-encoded SSL certificate
- **Usage**: For databases with self-signed or custom CA certificates
- **Example**:
```bash
cat /path/to/ca.pem | base64 -w 0
```
- **Notes**: Verify SSL/TLS connections for managed database services (RDS, Cloud SQL, Azure Database)
### DB_READ_REPLICAS
Optional JSON array of read-only database replicas.
- **Format**: JSON array of connection objects
- **Example**:
```json
[
{"connectionString": "postgresql://user:pass@replica1:5432/infisical"},
{"connectionString": "postgresql://user:pass@replica2:5432/infisical"}
]
```
- **Use Case**: Distribute read-heavy workloads across multiple database replicas
- **Requirements**: Read replicas must be in sync with primary
## Redis Configuration
### REDIS_URL
**Required** Redis connection string.
- **Format**: `redis://[:password@]host:port[/db]` or `rediss://...` for TLS
- **Examples**:
- Standard: `redis://redis.example.com:6379`
- With auth: `redis://:password@redis.example.com:6379`
- TLS: `rediss://redis.example.com:6380`
- **Requirements**: Redis 6.2 or newer
- **Important**: Redis Cluster mode is NOT supported; use standalone or Sentinel
### Redis Sentinel (High Availability)
Use these variables to configure Redis Sentinel for HA without Cluster mode.
#### REDIS_SENTINEL_HOSTS
Comma-separated list of Sentinel node addresses.
- **Format**: `host1:port1,host2:port2,host3:port3`
- **Example**: `sentinel1.example.com:26379,sentinel2.example.com:26379,sentinel3.example.com:26379`
#### REDIS_SENTINEL_MASTER_NAME
Name of the Redis master monitored by Sentinel.
- **Example**: `mymaster`
- **Default**: `mymaster` (if not specified)
#### REDIS_SENTINEL_ENABLE_TLS
Enable TLS for Sentinel connections.
- **Format**: `true` or `false`
- **Default**: `false`
#### REDIS_SENTINEL_USERNAME
Username for Sentinel authentication (if required).
#### REDIS_SENTINEL_PASSWORD
Password for Sentinel authentication.
## SMTP Configuration
SMTP is required for email-based features. Without SMTP configured, the following features are disabled:
- Multi-factor authentication (MFA) via email
- Email invitations
- Suspicious login alerts
- Password reset emails
### SMTP_HOST
**Required if SMTP enabled** SMTP server hostname.
- **Example**: `smtp.gmail.com`
### SMTP_PORT
SMTP server port.
- **Default**: `587` (STARTTLS)
- **Common Values**:
- `587` — STARTTLS (recommended)
- `465` — SMTPS (implicit TLS)
- `25` — Unencrypted (not recommended for production)
### SMTP_USERNAME
Username for SMTP authentication.
### SMTP_PASSWORD
Password for SMTP authentication.
### SMTP_FROM_ADDRESS
**Required if SMTP enabled** Email address from which emails are sent.
- **Example**: `noreply@infisical.com`
### SMTP_FROM_NAME
Display name for the sender.
- **Example**: `Infisical`
- **Default**: `Infisical`
### SMTP_REQUIRE_TLS
Require TLS connection (STARTTLS).
- **Format**: `true` or `false`
- **Default**: `true`
### SMTP_IGNORE_TLS
Ignore TLS certificate errors (useful for self-signed certificates in development).
- **Format**: `true` or `false`
- **Default**: `false`
- **Warning**: Do not use in production
## OAuth/SSO Configuration
### Google Login
To enable Google OAuth login, register an OAuth 2.0 application in Google Cloud Console.
#### CLIENT_ID_GOOGLE_LOGIN
Google OAuth client ID.
#### CLIENT_SECRET_GOOGLE_LOGIN
Google OAuth client secret.
### GitHub Login
Register an OAuth application at https://github.com/settings/developers.
#### CLIENT_ID_GITHUB_LOGIN
GitHub OAuth client ID.
#### CLIENT_SECRET_GITHUB_LOGIN
GitHub OAuth client secret.
### GitLab Login
Register an OAuth application in your GitLab instance (or gitlab.com).
#### CLIENT_ID_GITLAB_LOGIN
GitLab OAuth client ID.
#### CLIENT_SECRET_GITLAB_LOGIN
GitLab OAuth client secret.
## Authentication Timeouts
### JWT_AUTH_LIFETIME
Lifetime of access tokens.
- **Default**: `15m` (15 minutes)
- **Format**: Valid Node.js duration string (e.g., `30m`, `1h`)
### JWT_REFRESH_LIFETIME
Lifetime of refresh tokens.
- **Default**: `24h` (24 hours)
- **Format**: Valid Node.js duration string
## Enterprise and Licensing
### LICENSE_KEY
License key for Infisical Enterprise features.
- **Format**: Provided by Infisical upon enterprise subscription
- **Features Enabled**: SAML, RBAC advanced features, audit logs, IP allowlisting, etc.
## FIPS 140-2 Compliance
FIPS mode is enabled using the `infisical/infisical:latest-fips` image with additional Node.js configuration.
### FIPS_ENABLED
Enable FIPS 140-2 mode.
- **Format**: `true` or `false`
- **Default**: `false`
- **Requirement**: Must use `infisical/infisical:latest-fips` image
### NODE_OPTIONS
Node.js runtime options for FIPS compliance.
- **For FIPS Mode**:
```
NODE_OPTIONS="--max-old-space-size=8192 --force-fips"
```
- **Notes**:
- `--force-fips` enables FIPS mode
- `--max-old-space-size` allocates memory for the Node.js heap (adjust based on load)
## Telemetry
### TELEMETRY_ENABLED
Enable or disable telemetry collection.
- **Format**: `true` or `false`
- **Default**: `true`
### OTEL_EXPORT_TYPE
Export destination for OpenTelemetry metrics.
- **Options**: `prometheus`, `otlp`
- **Example**: `prometheus` exports metrics on `/metrics` endpoint for Prometheus scraping
## Web and Security
### SITE_URL
**Required** Public URL of the Infisical instance.
- **Format**: Full URL (e.g., `https://secrets.example.com`)
- **Usage**: Used for email links, OAuth redirects, and frontend configuration
### CORS_ALLOWED_ORIGINS
Comma-separated list of allowed CORS origins.
- **Format**: Full URLs (e.g., `https://app.example.com,https://admin.example.com`)
- **Default**: Allows same origin
- **Notes**: Whitelist specific origins in production; avoid wildcards (`*`)
### ALLOW_INTERNAL_IP_CONNECTIONS
Allow connections to internal IP addresses (useful for Kubernetes).
- **Format**: `true` or `false`
- **Default**: `false`
- **Use Case**: Kubernetes nodes using internal IPs, local Redis/PostgreSQL on private networks
## Summary: Minimal Configuration
For a minimal production deployment, these environment variables are required:
```bash
# Security
ENCRYPTION_KEY="<16-byte-hex>"
AUTH_SECRET="<base64-32-byte>"
# Database
DB_CONNECTION_URI="postgresql://user:pass@host:5432/infisical"
# Redis
REDIS_URL="redis://host:6379"
# Web
SITE_URL="https://secrets.example.com"
# SMTP (required for email features)
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USERNAME="[email protected]"
SMTP_PASSWORD="password"
SMTP_FROM_ADDRESS="[email protected]"
```
For additional features (OAuth, FIPS, Sentinel, etc.), add the relevant variables from the sections above.
@@ -0,0 +1,533 @@
# Kubernetes Deployment Guide
Deploy Infisical on Kubernetes using the official Helm chart for scalable, cloud-native deployments.
## Prerequisites
- Kubernetes 1.23 or newer
- Helm 3.11.3 or newer
- `kubectl` configured and authenticated to your cluster
- PostgreSQL 14+ (managed or in-cluster)
- Redis 6.2+ (managed or in-cluster)
## Helm Chart Installation
### Add the Infisical Helm Repository
```bash
helm repo add infisical https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/
helm repo update
```
### Create a Namespace
```bash
kubectl create namespace infisical
```
### Create Secrets
Before installing the chart, create a Kubernetes secret with required environment variables:
```bash
kubectl create secret generic infisical-secrets \
--from-literal=ENCRYPTION_KEY=$(openssl rand -hex 16) \
--from-literal=AUTH_SECRET=$(openssl rand -base64 32) \
--from-literal=DB_CONNECTION_URI="postgresql://user:password@postgres-host:5432/infisical" \
--from-literal=REDIS_URL="redis://redis-host:6379" \
--from-literal=SITE_URL="https://secrets.example.com" \
--from-literal=SMTP_HOST="smtp.example.com" \
--from-literal=SMTP_PORT="587" \
--from-literal=SMTP_USERNAME="[email protected]" \
--from-literal=SMTP_PASSWORD="password" \
--from-literal=SMTP_FROM_ADDRESS="[email protected]" \
-n infisical
```
### Install the Chart
```bash
helm install infisical infisical/infisical-standalone-postgres \
--namespace infisical \
--values values.yaml
```
## Values Configuration
Create a `values.yaml` file to customize the deployment:
```yaml
# Replica count for horizontal scaling
replicaCount: 3
image:
repository: infisical/infisical
tag: latest
pullPolicy: IfNotPresent
# Pod configuration
podAnnotations: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
# Resource limits
resources:
limits:
cpu: 2
memory: 4Gi
requests:
cpu: 500m
memory: 1Gi
# Service
service:
type: ClusterIP
port: 8080
# Environment variables from the secret
env:
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: infisical-secrets
key: ENCRYPTION_KEY
- name: AUTH_SECRET
valueFrom:
secretKeyRef:
name: infisical-secrets
key: AUTH_SECRET
- name: DB_CONNECTION_URI
valueFrom:
secretKeyRef:
name: infisical-secrets
key: DB_CONNECTION_URI
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: infisical-secrets
key: REDIS_URL
- name: SITE_URL
valueFrom:
secretKeyRef:
name: infisical-secrets
key: SITE_URL
- name: SMTP_HOST
valueFrom:
secretKeyRef:
name: infisical-secrets
key: SMTP_HOST
- name: SMTP_PORT
valueFrom:
secretKeyRef:
name: infisical-secrets
key: SMTP_PORT
- name: SMTP_USERNAME
valueFrom:
secretKeyRef:
name: infisical-secrets
key: SMTP_USERNAME
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: infisical-secrets
key: SMTP_PASSWORD
- name: SMTP_FROM_ADDRESS
valueFrom:
secretKeyRef:
name: infisical-secrets
key: SMTP_FROM_ADDRESS
# Persistence (for temporary files)
persistence:
enabled: true
storageClassName: standard
accessMode: ReadWriteOnce
size: 2Gi
mountPath: /tmp
# Ingress
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: secrets.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: infisical-tls
hosts:
- secrets.example.com
# Health checks
livenessProbe:
httpGet:
path: /api/status
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/status
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
# PostgreSQL (optional - if using in-cluster)
postgresql:
enabled: true
auth:
username: infisical
password: change-me-in-production
database: infisical
primary:
persistence:
size: 8Gi
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2
memory: 2Gi
# Redis (optional - if using in-cluster)
redis:
enabled: true
auth:
enabled: false
master:
persistence:
size: 2Gi
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
```
## Using External Databases
To use managed PostgreSQL and Redis (RDS, Cloud SQL, ElastiCache, etc.), disable the in-cluster services:
```yaml
postgresql:
enabled: false
redis:
enabled: false
```
Then configure the connection strings in the secret:
```bash
kubectl create secret generic infisical-secrets \
--from-literal=DB_CONNECTION_URI="postgresql://user:[email protected]:5432/infisical" \
--from-literal=REDIS_URL="rediss://redis-cluster.cache.amazonaws.com:6380" \
# ... other variables
-n infisical
```
## Scaling
### Horizontal Scaling
Increase the number of replicas in `values.yaml`:
```yaml
replicaCount: 5 # Scale to 5 replicas
```
Apply the change:
```bash
helm upgrade infisical infisical/infisical-standalone-postgres \
--namespace infisical \
--values values.yaml
```
Or use kubectl directly:
```bash
kubectl scale deployment infisical --replicas=5 -n infisical
```
### Autoscaling
Enable Horizontal Pod Autoscaler (HPA):
```yaml
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
```
## Pod Security
### Non-Root User
The default configuration runs Infisical as a non-root user (UID 1001):
```yaml
podSecurityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
```
### Pod Security Policy
For Kubernetes clusters with Pod Security Policies (PSP) enabled, ensure the Infisical deployment complies:
```bash
kubectl label pod -l app=infisical restricted=true -n infisical
```
## Networking
### Network Policy
Create a NetworkPolicy to isolate Infisical traffic:
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: infisical-network-policy
namespace: infisical
spec:
podSelector:
matchLabels:
app: infisical
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 5432 # PostgreSQL
- protocol: TCP
port: 6379 # Redis
- to:
- podSelector: {}
ports:
- protocol: TCP
port: 53 # DNS
```
### Ingress with TLS
Use cert-manager and Let's Encrypt for automated TLS:
```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: infisical-cert
namespace: infisical
spec:
secretName: infisical-tls
issuerRef:
name: letsencrypt-prod
commonName: secrets.example.com
dnsNames:
- secrets.example.com
```
Then configure Ingress:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: infisical-ingress
namespace: infisical
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- secrets.example.com
secretName: infisical-tls
rules:
- host: secrets.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: infisical
port:
number: 8080
```
## Persistence
Create PersistentVolumeClaims for PostgreSQL and Redis data:
```yaml
postgresql:
primary:
persistence:
enabled: true
storageClassName: fast-ssd
size: 20Gi
redis:
master:
persistence:
enabled: true
storageClassName: fast-ssd
size: 5Gi
```
## Monitoring and Logging
### Metrics
Infisical exposes metrics via the `/metrics` endpoint (OpenTelemetry format):
```bash
kubectl port-forward svc/infisical 8080:8080 -n infisical
curl http://localhost:8080/metrics
```
### Logs
View logs from all Infisical replicas:
```bash
kubectl logs -l app=infisical -n infisical --all-containers=true -f
```
### Prometheus Integration
Create a ServiceMonitor for Prometheus:
```yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: infisical
namespace: infisical
spec:
selector:
matchLabels:
app: infisical
endpoints:
- port: metrics
interval: 30s
path: /metrics
```
## Backup and Recovery
### Backup PostgreSQL
If using in-cluster PostgreSQL:
```bash
kubectl exec -it infisical-postgresql-0 -n infisical -- \
pg_dump -U infisical infisical | gzip > backup.sql.gz
```
For managed PostgreSQL (RDS, Cloud SQL), use the managed service's backup tools.
### Backup Redis
For in-cluster Redis:
```bash
kubectl exec -it infisical-redis-master-0 -n infisical -- \
redis-cli BGSAVE
kubectl cp infisical/infisical-redis-master-0:/data/dump.rdb ./redis_backup.rdb
```
## Troubleshooting
### Check Pod Status
```bash
kubectl get pods -n infisical
kubectl describe pod <pod-name> -n infisical
```
### View Logs
```bash
kubectl logs <pod-name> -n infisical
```
### Port Forward for Testing
```bash
kubectl port-forward svc/infisical 8080:8080 -n infisical
curl http://localhost:8080/api/status
```
### Check Events
```bash
kubectl get events -n infisical --sort-by='.lastTimestamp'
```
## Upgrading
To upgrade Infisical on Kubernetes:
1. Backup PostgreSQL (see Backup and Recovery section)
2. Update the chart:
```bash
helm repo update
```
3. Upgrade the release:
```bash
helm upgrade infisical infisical/infisical-standalone-postgres \
--namespace infisical \
--values values.yaml
```
4. Monitor the rollout:
```bash
kubectl rollout status deployment/infisical -n infisical
```
Schema migrations run automatically during pod startup.
@@ -0,0 +1,552 @@
# Scaling and High Availability Guide
Infisical is a stateless application designed to scale horizontally. This guide covers scaling patterns, sizing recommendations, high availability (HA) setup, and upgrade procedures.
## Architecture Overview
Infisical's stateless architecture means:
- **All state is external**: PostgreSQL stores data, Redis handles caching and job queues
- **Horizontal scaling**: Add more Infisical replicas without reconfiguration
- **Load balancing**: Multiple replicas distribute traffic evenly
- **Zero shared state**: Each replica is identical and independent
This enables seamless scaling from single-node deployments to large distributed clusters.
## Sizing Recommendations
Choose deployment sizes based on your organization's users, secrets, and API request volume.
### Small Deployment
**Use Case**: Development, testing, small organizations (< 50 users)
**Infisical**:
- Replicas: 2
- CPU: 2 cores per replica
- Memory: 4-8 GB per replica
- Storage: N/A (stateless)
**PostgreSQL**:
- vCPU: 2
- Memory: 8 GB
- Storage: 100 GB (SSD recommended)
- Configuration: Single instance with automated backups
**Redis**:
- vCPU: 2
- Memory: 4 GB
- Storage: N/A (in-memory)
- Configuration: Standalone (simplest for this size)
### Medium Deployment
**Use Case**: Production environments (50-500 users)
**Infisical**:
- Replicas: 5
- CPU: 2-4 cores per replica
- Memory: 4-8 GB per replica
- Storage: N/A (stateless)
**PostgreSQL**:
- vCPU: 4
- Memory: 16 GB
- Storage: 200 GB (SSD)
- Configuration: Primary + read replicas for load distribution
**Redis**:
- vCPU: 2
- Memory: 4 GB
- Configuration: Standalone or Sentinel for HA
### Large Deployment
**Use Case**: Enterprise environments (500+ users)
**Infisical**:
- Replicas: 10+
- CPU: 2-4 cores per replica
- Memory: 4-8 GB per replica
- Storage: N/A (stateless)
**PostgreSQL**:
- vCPU: 8
- Memory: 32 GB
- Storage: 500 GB+ (SSD with RAID)
- Configuration: Primary + multiple read replicas, automated backups and WAL archiving
**Redis**:
- vCPU: 2-4
- Memory: 4-8 GB
- Configuration: Redis Sentinel for HA or Redis Cluster (but Infisical does NOT support Cluster mode)
## Horizontal Scaling
### Docker Compose
To scale Infisical with Docker Compose, create multiple service definitions:
```yaml
version: '3.8'
services:
postgres:
image: postgres:14-alpine
environment:
POSTGRES_USER: infisical
POSTGRES_PASSWORD: password
POSTGRES_DB: infisical
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
infisical-1:
image: infisical/infisical:latest
depends_on:
- postgres
- redis
environment:
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
AUTH_SECRET: ${AUTH_SECRET}
DB_CONNECTION_URI: postgresql://infisical:password@postgres:5432/infisical
REDIS_URL: redis://redis:6379
SITE_URL: https://secrets.example.com
ports:
- "8001:8080"
infisical-2:
image: infisical/infisical:latest
depends_on:
- postgres
- redis
environment:
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
AUTH_SECRET: ${AUTH_SECRET}
DB_CONNECTION_URI: postgresql://infisical:password@postgres:5432/infisical
REDIS_URL: redis://redis:6379
SITE_URL: https://secrets.example.com
ports:
- "8002:8080"
infisical-3:
image: infisical/infisical:latest
depends_on:
- postgres
- redis
environment:
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
AUTH_SECRET: ${AUTH_SECRET}
DB_CONNECTION_URI: postgresql://infisical:password@postgres:5432/infisical
REDIS_URL: redis://redis:6379
SITE_URL: https://secrets.example.com
ports:
- "8003:8080"
nginx:
image: nginx:latest
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
depends_on:
- infisical-1
- infisical-2
- infisical-3
volumes:
postgres_data:
redis_data:
```
Use Nginx or HAProxy as a load balancer to distribute traffic:
```nginx
upstream infisical {
server infisical-1:8080;
server infisical-2:8080;
server infisical-3:8080;
}
server {
listen 80;
location / {
proxy_pass http://infisical;
}
}
```
### Kubernetes
Scale using kubectl:
```bash
kubectl scale deployment infisical --replicas=10 -n infisical
```
Or update the Helm values:
```yaml
replicaCount: 10
```
Then apply:
```bash
helm upgrade infisical infisical/infisical-standalone-postgres \
--namespace infisical \
-f values.yaml
```
## Database Replication
### PostgreSQL Read Replicas
For large deployments, use PostgreSQL read replicas to distribute read-heavy queries (secrets, audit logs):
```bash
DB_READ_REPLICAS='[
{"connectionString": "postgresql://user:[email protected]:5432/infisical"},
{"connectionString": "postgresql://user:[email protected]:5432/infisical"}
]'
```
Infisical will distribute SELECT queries across replicas while ensuring writes go to the primary.
### Setting Up AWS RDS Read Replicas
1. Create a read replica in AWS RDS:
```bash
aws rds create-db-instance-read-replica \
--db-instance-identifier infisical-replica-1 \
--source-db-instance-identifier infisical-primary
```
2. Configure in Infisical:
```bash
DB_READ_REPLICAS='[
{"connectionString": "postgresql://user:password@infisical-replica-1.123456789.us-east-1.rds.amazonaws.com:5432/infisical"}
]'
```
## Redis High Availability
Infisical supports Redis Sentinel for high availability. Cluster mode is NOT supported.
### Redis Sentinel Setup
Sentinel monitors Redis and automatically promotes a replica to master if the primary fails.
#### Configure Sentinel
Create `sentinel.conf`:
```
port 26379
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
```
Run three Sentinel nodes for quorum:
```bash
redis-sentinel sentinel-1.conf
redis-sentinel sentinel-2.conf
redis-sentinel sentinel-3.conf
```
#### Configure Infisical to Use Sentinel
```bash
REDIS_SENTINEL_HOSTS="sentinel1.example.com:26379,sentinel2.example.com:26379,sentinel3.example.com:26379"
REDIS_SENTINEL_MASTER_NAME="mymaster"
REDIS_SENTINEL_ENABLE_TLS="true"
REDIS_SENTINEL_USERNAME="sentinel-user"
REDIS_SENTINEL_PASSWORD="sentinel-password"
```
Infisical will discover the current Redis master through Sentinel and automatically handle failovers.
### Docker Compose with Sentinel
```yaml
redis-master:
image: redis:7-alpine
ports:
- "6379:6379"
redis-replica:
image: redis:7-alpine
command: redis-server --slaveof redis-master 6379
depends_on:
- redis-master
sentinel-1:
image: redis:7-alpine
command: redis-sentinel /sentinel.conf
volumes:
- ./sentinel.conf:/sentinel.conf
ports:
- "26379:26379"
sentinel-2:
image: redis:7-alpine
command: redis-sentinel /sentinel.conf
volumes:
- ./sentinel.conf:/sentinel.conf
ports:
- "26380:26379"
sentinel-3:
image: redis:7-alpine
command: redis-sentinel /sentinel.conf
volumes:
- ./sentinel.conf:/sentinel.conf
ports:
- "26381:26379"
infisical:
image: infisical/infisical:latest
environment:
REDIS_SENTINEL_HOSTS: "sentinel-1:26379,sentinel-2:26379,sentinel-3:26379"
REDIS_SENTINEL_MASTER_NAME: "mymaster"
```
## Backup and Disaster Recovery
### PostgreSQL Backup Strategy
**Automated Backups**:
For managed PostgreSQL (RDS, Cloud SQL), use automated backups:
```bash
# AWS RDS
aws rds create-db-snapshot \
--db-instance-identifier infisical \
--db-snapshot-identifier infisical-backup-$(date +%s)
```
**Manual Backups**:
For self-hosted PostgreSQL:
```bash
pg_dump -h pg.example.com -U infisical infisical | gzip > backup_$(date +%Y%m%d).sql.gz
```
**Point-in-Time Recovery** (if WAL archiving is configured):
```bash
# Configure WAL archiving in PostgreSQL postgresql.conf
archive_mode = on
archive_command = 'aws s3 cp %p s3://backup-bucket/wal_archive/%f'
```
Then restore to a specific point in time.
### Redis Backup
Redis backups are less critical than database backups (data can be repopulated from PostgreSQL), but they can speed up recovery:
```bash
redis-cli BGSAVE
redis-cli LASTSAVE # Shows timestamp of last snapshot
```
Backup the RDB file periodically:
```bash
cp /var/lib/redis/dump.rdb /backup/redis_$(date +%s).rdb
```
### Backup Schedule
- **PostgreSQL**: Daily automated backups + continuous WAL archiving
- **Redis**: Daily snapshots (optional, less critical)
- **Retention**: Keep at least 30 days of backups for compliance
### Test Restores
Regularly test restores in a non-production environment to ensure backup integrity.
## Upgrades
Upgrading Infisical with zero downtime:
1. **Backup the database** (critical):
```bash
pg_dump -h pg.example.com -U infisical infisical > backup.sql
```
2. **Check the upgrade path** (optional):
Visit https://app.infisical.com/upgrade-path to verify your upgrade path and any special steps.
3. **Update replicas incrementally**:
For Kubernetes with rolling updates:
```bash
kubectl set image deployment/infisical infisical=infisical/infisical:new-version -n infisical
```
The rolling update ensures some replicas stay running while others update.
4. **Monitor the rollout**:
```bash
kubectl rollout status deployment/infisical -n infisical
```
5. **Schema migrations run automatically** on startup (since v0.111.0-postgres):
- One instance acquires a lock
- Migrations run
- Other instances wait for migrations to complete
- Cluster is ready
6. **Rollback if needed**:
```bash
kubectl rollout undo deployment/infisical -n infisical
```
## Licensing and Compliance
### License Server IP Addresses
Enterprise Infisical installations require connectivity to the license server. Whitelist these IPs in your firewall:
- `13.248.249.247`
- `35.71.190.59`
Ensure outbound HTTPS (port 443) is allowed to these addresses.
## Monitoring and Observability
### Key Metrics to Monitor
- **CPU and Memory**: Per-replica resource utilization
- **Request Latency**: API response times
- **Error Rate**: 5xx errors, database connection errors
- **Database Connections**: Active connections, connection pool saturation
- **Redis Memory**: Memory usage and eviction
- **Database Query Time**: Slow query logs
### Prometheus Metrics
Infisical exposes metrics on `/metrics` (OpenTelemetry format):
```bash
curl http://infisical:8080/metrics
```
### Log Aggregation
Aggregate logs from all replicas using your logging platform:
```bash
# Docker Compose
docker-compose logs infisical | grep ERROR
# Kubernetes
kubectl logs -l app=infisical -n infisical --all-containers=true
```
## Performance Tuning
### PostgreSQL Tuning
For large deployments, optimize PostgreSQL:
```sql
-- Increase shared buffers (typically 25% of RAM)
ALTER SYSTEM SET shared_buffers = '8GB';
-- Increase effective cache size (typically 50-75% of RAM)
ALTER SYSTEM SET effective_cache_size = '24GB';
-- Increase work_mem for complex queries
ALTER SYSTEM SET work_mem = '8MB';
-- Reload configuration
SELECT pg_reload_conf();
```
### Redis Tuning
Increase maxmemory if needed:
```bash
redis-cli CONFIG SET maxmemory 4gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
```
### Connection Pool Tuning
Monitor connection pool saturation and adjust if needed:
```bash
# Check PostgreSQL max connections
psql -h pg.example.com -U infisical -d infisical -c "SHOW max_connections;"
```
Increase if you have many Infisical replicas:
```bash
ALTER SYSTEM SET max_connections = 400;
```
## Troubleshooting HA Setups
### Redis Sentinel Failover Not Triggering
Check Sentinel logs:
```bash
redis-cli -p 26379 SENTINEL MASTERS
redis-cli -p 26379 SENTINEL SLAVES mymaster
```
Ensure Sentinel nodes can communicate with Redis.
### Database Connection Pool Exhaustion
If you see "too many connections" errors:
1. Check current connections:
```bash
psql -c "SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname;"
```
2. Increase PostgreSQL max_connections
3. Reduce Infisical replicas or increase connection pool size
### Read Replica Lag
If read replicas are lagging, monitor replication lag:
```bash
# AWS RDS
aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,ReplicationLag]'
```
Lag > 1 second may cause stale reads. Infisical writes always use the primary.
## Capacity Planning
To estimate hardware needs:
- **Users**: 10 users per core for moderate activity
- **Secrets**: 1 million secrets per 10 GB of PostgreSQL storage
- **API Calls**: 1000 req/sec per 2 cores with 4 GB memory
- **Database Connections**: 20-50 per Infisical replica
Example for 200 users:
- Infisical: 3 replicas x 2 cores
- PostgreSQL: 4 vCPU, 16 GB RAM, 100 GB storage
- Redis: 2 vCPU, 4 GB RAM
Adjust based on actual monitoring and load testing.