auto deployment fix
Some checks failed
Deploy to Production / deploy (push) Failing after 2m55s

This commit is contained in:
adminuser 2025-10-28 12:33:31 +00:00
parent 26c3c0bb0e
commit 222ad13724
11 changed files with 396 additions and 158 deletions

View File

@ -10,21 +10,68 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
COMPOSE_PROJECT_NAME: voxblog COMPOSE_PROJECT_NAME: voxblog
INFISICAL_TOKEN: ${{ secrets.INFISICAL_TOKEN }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}
INFISICAL_CLI_IMAGE: infisical/cli:latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Create placeholder .env
run: touch .env
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Ensure .env file exists - name: Load secrets from Infisical
shell: bash
run: | run: |
if [ ! -f .env ]; then set -euo pipefail
echo ".env file is missing. Add it to the repository or provision it before deployment."
if [ -z "${INFISICAL_TOKEN}" ]; then
echo "INFISICAL_TOKEN is not configured"
exit 1 exit 1
fi fi
CLI_IMAGE="${INFISICAL_CLI_IMAGE:-infisical/cli:latest}"
docker pull "$CLI_IMAGE" >/dev/null
tmp_file=$(mktemp)
if [ -n "${INFISICAL_API_URL:-}" ]; then
docker run --rm \
-e INFISICAL_TOKEN="$INFISICAL_TOKEN" \
${INFISICAL_SITE_URL:+-e INFISICAL_SITE_URL="$INFISICAL_SITE_URL"} \
-e INFISICAL_API_URL="$INFISICAL_API_URL" \
"$CLI_IMAGE" export --format=dotenv > "$tmp_file"
elif [ -n "${INFISICAL_SITE_URL:-}" ]; then
api_url="${INFISICAL_SITE_URL%/}/api"
docker run --rm \
-e INFISICAL_TOKEN="$INFISICAL_TOKEN" \
-e INFISICAL_SITE_URL="$INFISICAL_SITE_URL" \
-e INFISICAL_API_URL="$api_url" \
"$CLI_IMAGE" export --format=dotenv > "$tmp_file"
else
docker run --rm \
-e INFISICAL_TOKEN="$INFISICAL_TOKEN" \
"$CLI_IMAGE" export --format=dotenv > "$tmp_file"
fi
# Persist a runtime .env so external checks that expect the file succeed.
cp "$tmp_file" .env
while IFS= read -r line || [ -n "$line" ]; do
if [ -z "$line" ] || [[ "$line" == \#* ]]; then
continue
fi
key="${line%%=*}"
value="${line#*=}"
echo "::add-mask::$value"
printf '%s=%s\n' "$key" "$value" >> "$GITHUB_ENV"
done < "$tmp_file"
rm -f "$tmp_file"
- name: Stop existing containers - name: Stop existing containers
run: docker-compose down || true run: docker-compose down || true

2
.gitignore vendored
View File

@ -7,8 +7,8 @@ node_modules/
/packages/**/dist/ /packages/**/dist/
# Env & secrets # Env & secrets
.env.local
.env .env
.env.local
.env.* .env.*
!.env.example !.env.example
apps/**/.env apps/**/.env

View File

@ -267,34 +267,66 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
COMPOSE_PROJECT_NAME: voxblog COMPOSE_PROJECT_NAME: voxblog
INFISICAL_TOKEN: ${{ secrets.INFISICAL_TOKEN }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}
INFISICAL_CLI_IMAGE: infisical/cli:latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Create placeholder .env
run: touch .env
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Create .env file - name: Load secrets from Infisical
shell: bash
run: | run: |
cat > .env << EOF set -euo pipefail
DB_ROOT_PASSWORD=${{ secrets.DB_ROOT_PASSWORD }}
DB_PASSWORD=${{ secrets.DB_PASSWORD }} if [ -z "${INFISICAL_TOKEN}" ]; then
DB_USER=${{ secrets.DB_USER }} echo "INFISICAL_TOKEN is not configured"
DB_NAME=${{ secrets.DB_NAME }} exit 1
DB_HOST=${{ secrets.DB_HOST }} fi
DB_PORT=${{ secrets.DB_PORT }}
ADMIN_PASSWORD=${{ secrets.ADMIN_PASSWORD }} CLI_IMAGE="${INFISICAL_CLI_IMAGE:-infisical/cli:latest}"
OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }} docker pull "$CLI_IMAGE" >/dev/null
GHOST_ADMIN_API_KEY=${{ secrets.GHOST_ADMIN_API_KEY }}
GHOST_ADMIN_API_URL=${{ secrets.GHOST_ADMIN_API_URL }} tmp_file=$(mktemp)
S3_BUCKET=${{ secrets.S3_BUCKET }} if [ -n "${INFISICAL_API_URL:-}" ]; then
S3_REGION=${{ secrets.S3_REGION }} docker run --rm \
S3_ACCESS_KEY=${{ secrets.S3_ACCESS_KEY }} -e INFISICAL_TOKEN="$INFISICAL_TOKEN" \
S3_SECRET_KEY=${{ secrets.S3_SECRET_KEY }} ${INFISICAL_SITE_URL:+-e INFISICAL_SITE_URL="$INFISICAL_SITE_URL"} \
S3_ENDPOINT=${{ secrets.S3_ENDPOINT }} -e INFISICAL_API_URL="$INFISICAL_API_URL" \
VITE_API_URL=${{ secrets.VITE_API_URL }} "$CLI_IMAGE" export --format=dotenv > "$tmp_file"
EOF elif [ -n "${INFISICAL_SITE_URL:-}" ]; then
api_url="${INFISICAL_SITE_URL%/}/api"
docker run --rm \
-e INFISICAL_TOKEN="$INFISICAL_TOKEN" \
-e INFISICAL_SITE_URL="$INFISICAL_SITE_URL" \
-e INFISICAL_API_URL="$api_url" \
"$CLI_IMAGE" export --format=dotenv > "$tmp_file"
else
docker run --rm \
-e INFISICAL_TOKEN="$INFISICAL_TOKEN" \
"$CLI_IMAGE" export --format=dotenv > "$tmp_file"
fi
cp "$tmp_file" .env
while IFS= read -r line || [ -n "$line" ]; do
if [ -z "$line" ] || [[ "$line" == \#* ]]; then
continue
fi
key="${line%%=*}"
value="${line#*=}"
echo "::add-mask::$value"
printf '%s=%s\n' "$key" "$value" >> "$GITHUB_ENV"
done < "$tmp_file"
rm -f "$tmp_file"
- name: Build and deploy - name: Build and deploy
run: | run: |
@ -319,73 +351,21 @@ jobs:
## Step 4: Deployment Script (Alternative to Gitea Actions) ## Step 4: Deployment Script (Alternative to Gitea Actions)
If Gitea Actions is not available, use a webhook + script approach: If Gitea Actions is not available, you can still trigger deployments by SSH, cron, or a webhook that calls `deploy.sh`. The script now:
- Prefers `INFISICAL_TOKEN` and (optionally) `INFISICAL_SITE_URL` to pull secrets from Infisical via the official CLI container.
- Falls back to a local `.env` file only when no token is exported (for development/testing).
- Runs the same build → up → migrate → health-check flow afterwards.
Before running it manually or from a webhook, export the token:
```bash ```bash
#!/bin/bash export INFISICAL_TOKEN=st.your_service_token
# deploy.sh export INFISICAL_SITE_URL=https://secrets.yourdomain.com # optional
./deploy.sh
set -e
echo "🚀 Starting deployment..."
# Pull latest code
echo "📥 Pulling latest code..."
git pull origin main
# Create .env if not exists
if [ ! -f .env ]; then
echo "⚠️ .env file not found! Please create it from .env.example"
exit 1
fi
# Stop existing containers
echo "🛑 Stopping existing containers..."
docker-compose down
# Build new images
echo "🔨 Building new images..."
docker-compose build --no-cache
# Start containers
echo "▶️ Starting containers..."
docker-compose up -d
# Wait for services to be ready
echo "⏳ Waiting for services..."
sleep 10
# Run migrations
echo "🗄️ Running database migrations..."
docker-compose exec -T api pnpm run drizzle:migrate
# Health check
echo "🏥 Health check..."
if curl -f http://localhost:3301/api/health; then
echo "✅ API is healthy"
else
echo "❌ API health check failed"
exit 1
fi
if curl -f http://localhost:3300; then
echo "✅ Admin is healthy"
else
echo "❌ Admin health check failed"
exit 1
fi
# Clean up
echo "🧹 Cleaning up old images..."
docker image prune -af --filter "until=24h"
echo "✅ Deployment complete!"
``` ```
Make it executable: Everything else inside the script remains unchanged; see [deploy.sh](deploy.sh) for details.
```bash
chmod +x deploy.sh
```
## Step 5: Gitea Webhook Setup ## Step 5: Gitea Webhook Setup
@ -548,14 +528,11 @@ sudo certbot --nginx -d voxblog.yourdomain.com
## Step 8: Environment Variables ## Step 8: Environment Variables
Create `.env` on your VPS: Provision secrets in Infisical instead of maintaining a long-lived `.env` on disk:
```bash
cd /path/to/voxblog
cp .env.example .env
nano .env
```
Fill in all values from `.env.example`. 1. Follow [INFISICAL_SETUP.md](INFISICAL_SETUP.md) to boot Infisical (already live at `https://secrets.pusula.blog`) and add VoxBlog secrets.
2. Create a production-scoped service token (scoped to the secret path you created).
3. Store the token securely; you'll export it whenever you deploy.
## Step 9: Initial Deployment ## Step 9: Initial Deployment
@ -565,9 +542,12 @@ cd /var/www # or your preferred location
git clone https://your-gitea-url/your-username/voxblog.git git clone https://your-gitea-url/your-username/voxblog.git
cd voxblog cd voxblog
# Create .env file # (Optional) Prepare local .env for development only
cp .env.example .env # cp .env.example .env && nano .env
nano .env # Fill in values
# Export Infisical token for production deployment
export INFISICAL_TOKEN=st.your_service_token
export INFISICAL_SITE_URL=https://secrets.pusula.blog
# Initial deployment # Initial deployment
./deploy.sh ./deploy.sh
@ -650,7 +630,7 @@ git checkout <previous-commit-hash>
docker system prune -a docker system prune -a
``` ```
5. **Use secrets management** - never commit `.env` to git 5. **Use secrets management** - keep secrets in Infisical, never commit `.env`
6. **Set up monitoring** (optional): 6. **Set up monitoring** (optional):
- Portainer for Docker management - Portainer for Docker management
@ -685,7 +665,7 @@ docker system prune -a --volumes
## Security Checklist ## Security Checklist
- [ ] Use strong passwords in `.env` - [ ] Infisical secrets configured with strong values
- [ ] Enable firewall (ufw) - [ ] Enable firewall (ufw)
- [ ] Keep Docker updated - [ ] Keep Docker updated
- [ ] Use SSL/TLS (HTTPS) - [ ] Use SSL/TLS (HTTPS)

View File

@ -122,12 +122,15 @@ Gitea detects push
git clone https://your-gitea-url/username/voxblog.git git clone https://your-gitea-url/username/voxblog.git
cd voxblog cd voxblog
# Configure environment # Load Infisical token (preferred)
cp .env.example .env export INFISICAL_TOKEN=st.your_service_token
nano .env # Fill in your values export INFISICAL_SITE_URL=https://secrets.pusula.blog
# Deploy! # Deploy!
./deploy.sh ./deploy.sh
# For local testing only
# cp .env.example .env && nano .env
``` ```
### 2. Set Up CI/CD ### 2. Set Up CI/CD
@ -150,9 +153,13 @@ sudo apt-get install webhook
# Configure webhook (see QUICK_START.md) # Configure webhook (see QUICK_START.md)
``` ```
### 3. Add Secrets (Gitea Actions only) ### 3. Configure Secrets (Gitea Actions only)
Repository → Settings → Secrets → Add all from `.env` Repository → Settings → Secrets:
- `INFISICAL_TOKEN` service token scoped to the production workspace/path.
- `INFISICAL_SITE_URL` `https://secrets.pusula.blog` (already running on your VPS).
All application variables now live inside Infisical instead of `.env`.
### 4. Push to Main ### 4. Push to Main
@ -164,9 +171,9 @@ git push origin main
🎉 **Auto-deployment triggered!** 🎉 **Auto-deployment triggered!**
## 🔧 Environment Variables ## 🔧 Secrets Inventory
All required variables in `.env`: Store these keys inside Infisical (`production` environment):
```bash ```bash
# Database (all use DB_* prefix) # Database (all use DB_* prefix)
@ -255,8 +262,8 @@ docker volume prune
## 🔐 Security Best Practices ## 🔐 Security Best Practices
- ✅ Use strong passwords in `.env` - ✅ Store strong secrets in Infisical and rotate them regularly
- ✅ Never commit `.env` to git (already in .gitignore) - ✅ Remove stray `.env` files from servers and keep them out of git (already ignored)
- ✅ Enable firewall: `sudo ufw enable` - ✅ Enable firewall: `sudo ufw enable`
- ✅ Use SSL/TLS (HTTPS) - ✅ Use SSL/TLS (HTTPS)
- ✅ Keep Docker updated - ✅ Keep Docker updated
@ -351,10 +358,10 @@ docker-compose exec api env | grep DATABASE
- [ ] Docker files created - [ ] Docker files created
- [ ] docker-compose.yml configured - [ ] docker-compose.yml configured
- [ ] .env file filled with production values - [ ] Infisical production workspace populated with VoxBlog secrets
- [ ] deploy.sh tested locally - [ ] deploy.sh tested locally
- [ ] CI/CD pipeline chosen and configured - [ ] CI/CD pipeline chosen and configured
- [ ] Secrets added to Gitea (if using Actions) - [ ] INFISICAL_TOKEN (+ optional INFISICAL_SITE_URL) added to Gitea secrets
- [ ] Domain DNS configured (optional) - [ ] Domain DNS configured (optional)
- [ ] Nginx reverse proxy set up (optional) - [ ] Nginx reverse proxy set up (optional)
- [ ] SSL certificate installed (optional) - [ ] SSL certificate installed (optional)

80
INFISICAL_SETUP.md Normal file
View File

@ -0,0 +1,80 @@
# Infisical Secret Management
This guide shows how to run (and maintain) the self-hosted Infisical instance for VoxBlog. A production instance is already running on this VPS at `https://secrets.pusula.blog` with files under `/home/adminuser/infisical`.
## 1. Start Infisical
1. Copy the sample environment:
```bash
cp infisical/.env.example infisical/.env
```
2. Edit `infisical/.env` and set:
- `INFISICAL_SITE_URL=https://secrets.pusula.blog`.
- `INFISICAL_POSTGRES_PASSWORD` — database password (strong, unique).
- `INFISICAL_AUTH_SECRET` — 32-byte base64 secret (`openssl rand -base64 32`).
- Leave `INFISICAL_ENCRYPTION_KEY` blank and set `INFISICAL_ROOT_ENCRYPTION_KEY` to a 32-byte base64 secret (`openssl rand -base64 32`).
- Set `INFISICAL_DATABASE_URL=postgresql://infisical:${INFISICAL_POSTGRES_PASSWORD}@postgres:5432/infisical`.
3. Boot the stack:
```bash
docker compose \
--env-file infisical/.env \
-f infisical/docker-compose.yml \
up -d
```
4. Point your reverse proxy (Caddy is already configured) at `http://127.0.0.1:8080` so the public URL works over HTTPS.
## 2. Bootstrap Infisical
1. Visit `INFISICAL_SITE_URL` and create the initial admin account.
2. Create a **Workspace** (e.g. `voxblog`).
3. Add environments you need (at least `production`, maybe `staging`/`development`).
4. Inside each environment, create a **secret path** (e.g. `/`) and add the VoxBlog variables:
- `MYSQL_ROOT_PASSWORD`
- `MYSQL_PASSWORD`
- `ADMIN_PASSWORD`
- `OPENAI_API_KEY`
- `GHOST_ADMIN_API_KEY`
- `GHOST_ADMIN_API_URL`
- `S3_BUCKET`
- `S3_REGION`
- `S3_ACCESS_KEY`
- `S3_SECRET_KEY`
- `S3_ENDPOINT`
- `VITE_API_URL`
## 3. Service Token for Automation
1. In the workspace, open **Integration → Service Tokens → Create Token**.
2. Scope the token to the `production` environment and the secret path containing the keys (usually `/`).
3. Copy the token value and store it somewhere safe—you will not see it again.
## 4. Wire Deployments
### Gitea Actions
1. In your VoxBlog repository, go to **Settings → Secrets** and add:
- `INFISICAL_TOKEN` — the service token from the previous step.
- `INFISICAL_SITE_URL``https://secrets.pusula.blog`.
2. No other secret variables are needed; the workflow now loads them dynamically before running Docker Compose.
### Manual / Webhook Deployments
1. On the VPS, export the token before running `deploy.sh`:
```bash
export INFISICAL_TOKEN=st.your_token_value
export INFISICAL_SITE_URL=https://secrets.pusula.blog
./deploy.sh
```
2. The script prefers Infisical; it only falls back to `.env` when no token is set, so consider removing any old `.env` file from the server.
## 5. Rotating Secrets
1. Update the value inside Infisical.
2. Re-run the deployment pipeline (or `deploy.sh`) so new containers launch with the rotated configuration.
3. Old values never touch disk—no extra clean-up is required.
## 6. Backups & Maintenance
- Backup the Postgres volume (`infisical-postgres-data`) using your usual VPS backup process.
- Protect the Infisical site with HTTPS and, ideally, IP allow-lists or SSO.
- Rotate the service token periodically; update the Gitea secret and any server-side exports at the same time.

View File

@ -20,29 +20,30 @@ git clone https://your-gitea-url/username/voxblog.git
cd voxblog cd voxblog
``` ```
### Step 2: Configure Environment ### Step 2: Configure Secrets
Recommended (production): export your Infisical service token so the deployment scripts can pull secrets on demand.
```bash ```bash
# Copy example env file # Export the service token (see INFISICAL_SETUP.md)
cp .env.example .env export INFISICAL_TOKEN=st.your_service_token
export INFISICAL_SITE_URL=https://secrets.pusula.blog
# Edit with your values export INFISICAL_API_URL=https://secrets.pusula.blog/api # optional, auto-derived otherwise
nano .env
``` ```
Fill in all values: Fallback for local-only testing:
- `DB_ROOT_PASSWORD` - Strong password for MySQL root
- `DB_PASSWORD` - Password for voxblog database user ```bash
- `DB_USER` - Database username (default: voxblog) cp .env.example .env
- `DB_NAME` - Database name (default: voxblog) nano .env # never commit this file
- `DB_HOST` - Database host (default: localhost) ```
- `DB_PORT` - Database port (default: 3306)
- `ADMIN_PASSWORD` - Password for admin login Whether Infisical or a temporary `.env` is used, ensure these variables exist:
- `OPENAI_API_KEY` - Your OpenAI API key - `DB_ROOT_PASSWORD`, `DB_PASSWORD`, `DB_USER`, `DB_NAME`, `DB_HOST`, `DB_PORT`
- `GHOST_ADMIN_API_KEY` - Your Ghost CMS API key - `ADMIN_PASSWORD`, `OPENAI_API_KEY`
- `GHOST_ADMIN_API_URL` - Ghost Admin API base URL (e.g., https://ghost.example.com) - `GHOST_ADMIN_API_KEY`, `GHOST_ADMIN_API_URL`
- `S3_*` - Your S3 credentials - `S3_BUCKET`, `S3_REGION`, `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `S3_ENDPOINT`
- `VITE_API_URL` - Your API URL (e.g., https://api.yourdomain.com) - `VITE_API_URL`
### Step 3: Deploy ### Step 3: Deploy
@ -104,22 +105,10 @@ sudo systemctl status gitea-runner
Go to: Repository → Settings → Secrets → Actions Go to: Repository → Settings → Secrets → Actions
Add all variables from `.env`: Add:
- `DB_ROOT_PASSWORD` - `INFISICAL_TOKEN` — service token scoped to VoxBlog production.
- `DB_PASSWORD` - `INFISICAL_SITE_URL` — Infisical base URL (optional when self-hosting).
- `DB_USER` - `INFISICAL_API_URL` — Infisical API endpoint (optional; defaults to `${SITE_URL}/api`).
- `DB_NAME`
- `DB_HOST`
- `DB_PORT`
- `ADMIN_PASSWORD`
- `OPENAI_API_KEY`
- `GHOST_ADMIN_API_KEY`
- `S3_BUCKET`
- `S3_REGION`
- `S3_ACCESS_KEY`
- `S3_SECRET_KEY`
- `S3_ENDPOINT`
- `VITE_API_URL`
3. **Push to main branch** - Deployment will trigger automatically! 3. **Push to main branch** - Deployment will trigger automatically!
@ -334,7 +323,7 @@ docker-compose exec mysql mysqldump -u voxblog -p voxblog > db-backup-$(date +%Y
## 🔐 Security Checklist ## 🔐 Security Checklist
- [ ] Strong passwords in `.env` - [ ] Infisical secrets created with strong values
- [ ] Firewall enabled (ufw) - [ ] Firewall enabled (ufw)
- [ ] SSH key-based authentication - [ ] SSH key-based authentication
- [ ] SSL/TLS enabled (HTTPS) - [ ] SSL/TLS enabled (HTTPS)
@ -344,12 +333,12 @@ docker-compose exec mysql mysqldump -u voxblog -p voxblog > db-backup-$(date +%Y
## 🎯 Production Checklist ## 🎯 Production Checklist
- [ ] `.env` file configured with production values - [ ] Infisical production workspace populated
- [ ] Domain name pointed to VPS - [ ] Domain name pointed to VPS
- [ ] SSL certificate installed - [ ] SSL certificate installed
- [ ] Nginx reverse proxy configured - [ ] Nginx reverse proxy configured
- [ ] Gitea Actions/Webhook set up - [ ] Gitea Actions/Webhook set up
- [ ] Secrets added to Gitea - [ ] INFISICAL_TOKEN (+ optional INFISICAL_SITE_URL) saved in Gitea secrets
- [ ] Backup strategy in place - [ ] Backup strategy in place
- [ ] Monitoring set up - [ ] Monitoring set up
- [ ] Firewall configured - [ ] Firewall configured

View File

@ -1,9 +1,13 @@
import { defineConfig } from 'drizzle-kit'; import { defineConfig } from 'drizzle-kit';
import fs from 'fs';
import path from 'path'; import path from 'path';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
// Load root .env so CLI has DB creds // Load root .env so CLI has DB creds when available
dotenv.config({ path: path.resolve(__dirname, '../../.env') }); const envPath = path.resolve(__dirname, '../../.env');
if (fs.existsSync(envPath)) {
dotenv.config({ path: envPath });
}
export default defineConfig({ export default defineConfig({
schema: './src/db/schema.ts', schema: './src/db/schema.ts',

View File

@ -1,6 +1,11 @@
import fs from 'fs';
import path from 'path'; import path from 'path';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
dotenv.config({ path: path.resolve(__dirname, '../../../.env') });
const envPath = path.resolve(__dirname, '../../../.env');
if (fs.existsSync(envPath)) {
dotenv.config({ path: envPath });
}
import express from 'express'; import express from 'express';
import cors from 'cors'; import cors from 'cors';
import morgan from 'morgan'; import morgan from 'morgan';

View File

@ -11,12 +11,63 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
# Check if .env exists fetch_env_from_infisical() {
if [ ! -f .env ]; then if [ -z "${INFISICAL_TOKEN:-}" ]; then
echo -e "${RED}.env file not found!${NC}" echo -e "${RED}INFISICAL_TOKEN is not set${NC}"
echo "Please create .env file from .env.example" echo "Provide an Infisical service token or create a .env file for local use."
exit 1 exit 1
fi fi
echo -e "${YELLOW}🔐 Retrieving secrets from Infisical...${NC}"
local tmp_env
tmp_env=$(mktemp)
local cli_image
cli_image="${INFISICAL_CLI_IMAGE:-infisical/cli:latest}"
# shellcheck disable=SC2206
local docker_cmd=(docker run --rm -e INFISICAL_TOKEN="${INFISICAL_TOKEN}")
if [ -n "${INFISICAL_SITE_URL:-}" ]; then
docker_cmd+=(-e INFISICAL_SITE_URL="${INFISICAL_SITE_URL}")
fi
if [ -n "${INFISICAL_API_URL:-}" ]; then
docker_cmd+=(-e INFISICAL_API_URL="${INFISICAL_API_URL}")
elif [ -n "${INFISICAL_SITE_URL:-}" ]; then
local api_url
api_url="${INFISICAL_SITE_URL%/}/api"
docker_cmd+=(-e INFISICAL_API_URL="${api_url}")
fi
docker_cmd+=("${cli_image}" export --format=dotenv)
if ! "${docker_cmd[@]}" >"${tmp_env}"; then
echo -e "${RED}❌ Failed to export secrets from Infisical${NC}"
rm -f "${tmp_env}"
exit 1
fi
set -o allexport
# shellcheck source=/dev/null
source "${tmp_env}"
set +o allexport
rm -f "${tmp_env}"
}
load_environment() {
if [ -n "${INFISICAL_TOKEN:-}" ]; then
fetch_env_from_infisical
elif [ -f .env ]; then
echo -e "${YELLOW}⚠️ Using local .env file (not recommended for production)...${NC}"
set -o allexport
# shellcheck source=/dev/null
source .env
set +o allexport
else
echo -e "${RED}❌ No environment configuration found${NC}"
echo "Provide INFISICAL_TOKEN (preferred) or create a local .env for testing."
exit 1
fi
}
load_environment
# Pull latest code # Pull latest code
echo -e "${YELLOW}📥 Pulling latest code...${NC}" echo -e "${YELLOW}📥 Pulling latest code...${NC}"

9
infisical/.env.example Normal file
View File

@ -0,0 +1,9 @@
# Infisical self-hosted configuration
INFISICAL_SITE_URL=https://secrets.pusula.blog
INFISICAL_POSTGRES_PASSWORD=change-this-password
# 32-byte base64 secrets; use `openssl rand -base64 32`
INFISICAL_ENCRYPTION_KEY=
INFISICAL_ROOT_ENCRYPTION_KEY=replace-with-base64
INFISICAL_AUTH_SECRET=replace-with-base64
INFISICAL_DATABASE_URL=postgresql://infisical:${INFISICAL_POSTGRES_PASSWORD}@postgres:5432/infisical
INFISICAL_TELEMETRY_ENABLED=false

View File

@ -0,0 +1,66 @@
services:
postgres:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_USER: infisical
POSTGRES_PASSWORD: ${INFISICAL_POSTGRES_PASSWORD:?set in infisical.env}
POSTGRES_DB: infisical
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- infisical
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--save", "20", "1", "--loglevel", "warning"]
volumes:
- redis-data:/data
networks:
- infisical
infisical:
image: infisical/infisical:latest
restart: unless-stopped
depends_on:
- postgres
- redis
environment:
NODE_ENV: production
PORT: ${INFISICAL_PORT:-8080}
HOST: 0.0.0.0
SITE_URL: ${INFISICAL_SITE_URL}
NEXTAUTH_URL: ${INFISICAL_SITE_URL}
NEXT_PUBLIC_SITE_URL: ${INFISICAL_SITE_URL}
ENCRYPTION_KEY: ${INFISICAL_ENCRYPTION_KEY:-}
ROOT_ENCRYPTION_KEY: ${INFISICAL_ROOT_ENCRYPTION_KEY:?generate_base64_secret}
AUTH_SECRET: ${INFISICAL_AUTH_SECRET:?generate_base64_secret}
NEXTAUTH_SECRET: ${INFISICAL_AUTH_SECRET:?generate_base64_secret}
REDIS_URL: redis://redis:6379
DATABASE_URL: ${INFISICAL_DATABASE_URL:?computed_in_env_file}
DATABASE_URL_NON_POOLING: ${INFISICAL_DATABASE_URL:?computed_in_env_file}
DATABASE_HOST: postgres
DATABASE_PORT: 5432
DATABASE_USERNAME: infisical
DATABASE_PASSWORD: ${INFISICAL_POSTGRES_PASSWORD:?set in infisical.env}
DATABASE_NAME: infisical
DB_CONNECTION_URI: ${INFISICAL_DATABASE_URL:?computed_in_env_file}
DB_HOST: postgres
DB_PORT: 5432
DB_USER: infisical
DB_PASSWORD: ${INFISICAL_POSTGRES_PASSWORD:?set in infisical.env}
DB_NAME: infisical
TELEMETRY_ENABLED: ${INFISICAL_TELEMETRY_ENABLED:-false}
ports:
- "127.0.0.1:${INFISICAL_PORT:-8080}:8080"
networks:
- infisical
networks:
infisical:
driver: bridge
volumes:
postgres-data:
redis-data: