From 7c24f1ecead8c4d0dd0df65d10d6338b0ea14078 Mon Sep 17 00:00:00 2001 From: Nate Emmert Date: Wed, 11 Mar 2026 08:12:06 -0400 Subject: [PATCH] Add Rocky Podman/Cockpit deployment fixes --- DEPLOYMENT.md | 141 +++++++++++++++++++++++++++++++++++++-------- README.md | 23 ++++++-- deploy.sh | 38 +++++++----- docker-compose.yml | 2 +- install.sh | 60 +++++++++++-------- next.config.mjs | 6 ++ next.config.ts | 8 --- 7 files changed, 201 insertions(+), 77 deletions(-) create mode 100644 next.config.mjs delete mode 100644 next.config.ts diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 700ad02..f907e15 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,4 +1,59 @@ -# Capsule Budget - ZimaOS Deployment Guide +# Capsule Budget Deployment Guide + +## Rocky Linux + Cockpit + Podman (Recommended) + +This is the easiest path for Rocky Linux servers managed with Cockpit. + +### 1) Install prerequisites on Rocky Linux + +```bash +sudo dnf install -y podman podman-compose cockpit cockpit-podman git +sudo systemctl enable --now cockpit.socket +``` + +Optional firewall rules: + +```bash +sudo firewall-cmd --add-service=cockpit --permanent +sudo firewall-cmd --add-port=7654/tcp --permanent +sudo firewall-cmd --reload +``` + +### 2) Clone and configure Capsule + +```bash +git clone https://github.com/nmemmert/budget.git capsule-budget +cd capsule-budget +cp .env.example .env +``` + +Generate and set encryption key: + +```bash +openssl rand -base64 32 +# paste the value into .env as ENCRYPTION_KEY=... +``` + +### 3) Deploy with Podman Compose + +```bash +podman-compose up -d --build +``` + +If your Podman version provides the compose subcommand, this also works: + +```bash +podman compose up -d --build +``` + +### 4) Manage in Cockpit + +1. Open Cockpit at `https://your-server:9090` +2. Go to **Podman Containers** +3. Verify `capsule-budget` is running +4. Use Logs/Start/Stop/Restart directly from Cockpit + +Access Capsule at: `http://your-server:7654` ## Installation Methods @@ -39,7 +94,7 @@ curl -fsSL https://raw.githubusercontent.com/nmemmert/budget/master/install.sh | This will: - Generate a secure encryption key - Clear any test data - - Build the Docker image + - Build the container image - Start the container 3. **Access Capsule:** @@ -67,23 +122,23 @@ If you prefer manual setup: 4. **Build and start:** ```bash - docker-compose up -d + podman-compose up -d ``` ## Data Persistence -**IMPORTANT: Your data is safely stored outside the Docker container** +**IMPORTANT: Your data is safely stored outside the container** ### How It Works -The Docker setup uses a **bind mount** to persist data: +The compose setup uses a **bind mount** to persist data: ```yaml volumes: - - ./data:/app/data # Host directory : Container directory + - ./data:/app/data:Z # Host directory : Container directory ``` -- **Host Location**: `./data/` (on your ZimaOS filesystem) +- **Host Location**: `./data/` (on your host filesystem) - **Container Location**: `/app/data/` (inside the container) - **What's Stored**: - User credentials (hashed) @@ -95,13 +150,13 @@ volumes: ✅ Container restarts ✅ Container rebuilds -✅ Docker Compose down/up +✅ Podman Compose down/up ✅ System reboots (with restart: unless-stopped) ### Data is Lost If ❌ You delete the `./data` directory -❌ You run `docker-compose down -v` (removes volumes) +❌ You run `podman-compose down -v` (removes volumes) ### Testing Persistence @@ -134,16 +189,17 @@ tar -xzf capsule-backup-YYYYMMDD.tar.gz - Enable automatic snapshots for the Capsule directory - Or use ZimaOS built-in backup features -### Data Location on ZimaOS +### Data Location on Rocky Linux / Podman Depending on where you deploy: - **SMB/File Manager**: Check the upload location - **SSH Deployment**: Usually `/mnt/your-pool/apps/capsule/data` -- **Docker Apps**: May be in `/var/lib/docker/volumes/` +- **Rootful Podman**: Usually under `/var/lib/containers/storage/` +- **Rootless Podman**: Usually under `~/.local/share/containers/storage/` To find exact location: ```bash -docker inspect capsule-budget | grep -A 10 "Mounts" +podman inspect capsule-budget | grep -A 10 "Mounts" ``` ## ZimaOS Integration @@ -183,20 +239,20 @@ cp -r data data-backup-$(date +%Y%m%d) ```bash # View logs -docker-compose logs -f +podman-compose logs -f # Stop Capsule -docker-compose stop +podman-compose stop # Restart Capsule -docker-compose restart +podman-compose restart # Stop and remove container -docker-compose down +podman-compose down # Rebuild after updates -docker-compose build --no-cache -docker-compose up -d +podman-compose build --no-cache +podman-compose up -d ``` ## Updating Capsule @@ -206,9 +262,9 @@ docker-compose up -d git pull # Rebuild and restart -docker-compose down -docker-compose build -docker-compose up -d +podman-compose down +podman-compose build +podman-compose up -d ``` Your data in `./data/` will persist across updates. @@ -225,12 +281,51 @@ Your data in `./data/` will persist across updates. ### Container won't start ```bash # Check logs -docker-compose logs +podman-compose logs # Verify .env file exists ls -la .env ``` +### Error: Failed to transpile next.config.ts / Cannot find module 'typescript' + +Cause: production containers prune devDependencies, and `next.config.ts` requires TypeScript at runtime. + +Fix: +```bash +# Pull latest changes that include next.config.mjs +git pull + +# Rebuild image without cache and restart +podman-compose down +podman-compose build --no-cache +podman-compose up -d +``` + +### Error: EACCES permission denied on /app/data/locks + +Cause: bind mount permissions/labels are not writable for the Podman container context. + +Fix: +```bash +# Stop container +podman-compose down + +# Ensure data dir exists and is writable +mkdir -p data +chmod 0777 data + +# Rebuild and restart (compose now uses :Z,U) +podman-compose build --no-cache +podman-compose up -d +``` + +If SELinux is enforcing and issues persist: +```bash +ls -ldZ data +podman unshare chown -R 0:0 data +``` + ### Port already in use Edit `docker-compose.yml` and change port mapping: ```yaml @@ -248,4 +343,4 @@ chmod 755 data For issues or questions: - GitHub: https://github.com/nmemmert/budget -- Check logs: `docker-compose logs -f` +- Check logs: `podman-compose logs -f` diff --git a/README.md b/README.md index c5ec1a6..2c440b6 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ A modern, privacy-focused envelope budgeting application built with Next.js, Typ ## Getting Started -### Docker Installation (Recommended for ZimaOS) +### Container Installation (Recommended for Rocky Linux + Cockpit) **Option 1: Clone and Deploy** (works for private/public repos) @@ -77,6 +77,19 @@ curl -fsSL https://raw.githubusercontent.com/nmemmert/budget/master/install.sh | **Access at:** `http://localhost:7654` or `http://your-device-ip:7654` +### Rocky Linux + Cockpit + Podman + +```bash +sudo dnf install -y podman podman-compose cockpit cockpit-podman git +sudo systemctl enable --now cockpit.socket + +git clone https://github.com/nmemmert/budget.git capsule-budget +cd capsule-budget +./deploy.sh +``` + +Manage the container in Cockpit at `https://your-server:9090` under **Podman Containers**. + ### Manual Installation (Development) If you want to run from source: @@ -304,19 +317,19 @@ Date,Amount,Description,Category ## Deployment -### ZimaOS Deployment (Recommended) +### Self-Hosted Deployment (Recommended) -Capsule is designed for self-hosted deployment on ZimaOS and similar platforms. +Capsule is designed for self-hosted deployment on Rocky Linux, ZimaOS, and similar platforms. **Quick Deploy:** ```bash ./deploy.sh ``` -See [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed ZimaOS deployment instructions. +See [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed Podman/Docker deployment instructions. **Features:** -- Docker containerization for easy deployment +- Podman/Docker containerization for easy deployment - Persistent data storage in `./data` directory - Health checks and auto-restart - Encrypted local storage (no cloud required) diff --git a/deploy.sh b/deploy.sh index 5495bbf..52676c3 100755 --- a/deploy.sh +++ b/deploy.sh @@ -7,18 +7,22 @@ set -e echo "🚀 Deploying Capsule to ZimaOS..." echo "" -# Detect docker compose command -if command -v docker-compose &> /dev/null; then - DOCKER_COMPOSE="docker-compose" -elif docker compose version &> /dev/null 2>&1; then - DOCKER_COMPOSE="docker compose" +# Detect container compose command (Podman first, then Docker) +if command -v podman-compose &> /dev/null; then + CONTAINER_COMPOSE="podman-compose" +elif command -v podman &> /dev/null && podman compose version &> /dev/null 2>&1; then + CONTAINER_COMPOSE="podman compose" +elif command -v docker-compose &> /dev/null; then + CONTAINER_COMPOSE="docker-compose" +elif command -v docker &> /dev/null && docker compose version &> /dev/null 2>&1; then + CONTAINER_COMPOSE="docker compose" else - echo "❌ Docker Compose not found" - echo "Please install Docker Compose: https://docs.docker.com/compose/install/" + echo "❌ No supported compose command found" + echo "Install one of: podman-compose, podman compose, docker-compose, docker compose" exit 1 fi -echo "✅ Using: $DOCKER_COMPOSE" +echo "✅ Using: $CONTAINER_COMPOSE" echo "" # Check if .env file exists @@ -59,17 +63,19 @@ fi # Clear test data echo "🧹 Clearing test data..." +mkdir -p data +chmod 0777 data || true rm -rf data/* echo "✅ Test data cleared" echo "" # Build and start containers -echo "🔨 Building Docker image..." -$DOCKER_COMPOSE build +echo "🔨 Building container image..." +$CONTAINER_COMPOSE build echo "" echo "🚀 Starting Capsule..." -$DOCKER_COMPOSE up -d +$CONTAINER_COMPOSE up -d echo "" echo "⏳ Waiting for container to start..." @@ -78,7 +84,7 @@ sleep 5 # Verify data directory is mounted echo "" echo "🔍 Verifying data persistence..." -if $DOCKER_COMPOSE exec capsule ls -la /app/data >/dev/null 2>&1; then +if $CONTAINER_COMPOSE exec capsule ls -la /app/data >/dev/null 2>&1; then echo "✅ Data directory is correctly mounted in container" else echo "⚠️ Warning: Could not verify data directory mount" @@ -92,10 +98,10 @@ echo " http://localhost:7654" echo " http://$(hostname -I | awk '{print $1}'):7654" echo "" echo "🔧 Useful commands:" -echo " $DOCKER_COMPOSE logs -f # View logs" -echo " $DOCKER_COMPOSE stop # Stop container" -echo " $DOCKER_COMPOSE restart # Restart container" -echo " $DOCKER_COMPOSE down # Stop and remove container" +echo " $CONTAINER_COMPOSE logs -f # View logs" +echo " $CONTAINER_COMPOSE stop # Stop container" +echo " $CONTAINER_COMPOSE restart # Restart container" +echo " $CONTAINER_COMPOSE down # Stop and remove container" echo "" echo "💾 Your data is stored in: ./data/" echo " - This directory persists across container restarts" diff --git a/docker-compose.yml b/docker-compose.yml index 95fdaa1..b06c0f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: - "7654:7654" volumes: # Persist user data outside container - - ./data:/app/data + - ./data:/app/data:Z,U environment: - NODE_ENV=production # Generate a secure key: openssl rand -base64 32 diff --git a/install.sh b/install.sh index 0962bbf..ebbb068 100755 --- a/install.sh +++ b/install.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Capsule Budget - One-Line Installer for ZimaOS/Docker +# Capsule Budget - One-Line Installer for ZimaOS/Podman/Docker # Usage: curl -fsSL https://raw.githubusercontent.com/nmemmert/budget/master/install.sh | bash set -e @@ -16,25 +16,36 @@ echo "║ ║" echo "╚════════════════════════════════════════════════════════════╝" echo "" -# Check for Docker +# Check for container engine echo "🔍 Checking prerequisites..." -if ! command -v docker &> /dev/null; then - echo "❌ Docker is not installed" - echo "Please install Docker first: https://docs.docker.com/get-docker/" +if command -v podman &> /dev/null; then + CONTAINER_ENGINE="podman" + echo "✅ Podman found" +elif command -v docker &> /dev/null; then + CONTAINER_ENGINE="docker" + echo "✅ Docker found" +else + echo "❌ No supported container engine found" + echo "Install Podman (recommended on Rocky Linux) or Docker" exit 1 fi -echo "✅ Docker found" -# Check for Docker Compose -if command -v docker-compose &> /dev/null; then - DOCKER_COMPOSE="docker-compose" - echo "✅ Docker Compose found (standalone)" -elif docker compose version &> /dev/null 2>&1; then - DOCKER_COMPOSE="docker compose" - echo "✅ Docker Compose found (plugin)" +# Check for compose command (Podman first) +if command -v podman-compose &> /dev/null; then + CONTAINER_COMPOSE="podman-compose" + echo "✅ podman-compose found" +elif command -v podman &> /dev/null && podman compose version &> /dev/null 2>&1; then + CONTAINER_COMPOSE="podman compose" + echo "✅ podman compose found" +elif command -v docker-compose &> /dev/null; then + CONTAINER_COMPOSE="docker-compose" + echo "✅ docker-compose found" +elif command -v docker &> /dev/null && docker compose version &> /dev/null 2>&1; then + CONTAINER_COMPOSE="docker compose" + echo "✅ docker compose found" else - echo "❌ Docker Compose is not installed" - echo "Please install Docker Compose: https://docs.docker.com/compose/install/" + echo "❌ No supported compose command found" + echo "Install one of: podman-compose, podman compose, docker-compose, docker compose" exit 1 fi @@ -127,23 +138,24 @@ fi # Create data directory mkdir -p data +chmod 0777 data || true echo "✅ Data directory created" # Build and start echo "" -echo "🔨 Building Docker image..." -$DOCKER_COMPOSE build +echo "🔨 Building container image..." +$CONTAINER_COMPOSE build echo "" echo "🚀 Starting Capsule Budget..." -$DOCKER_COMPOSE up -d +$CONTAINER_COMPOSE up -d # Wait for container echo "⏳ Waiting for container to start..." sleep 5 # Verify container is running -if $DOCKER_COMPOSE ps | grep -q "Up"; then +if $CONTAINER_COMPOSE ps | grep -q "Up"; then echo "" echo "╔════════════════════════════════════════════════════════════╗" echo "║ ║" @@ -164,10 +176,10 @@ if $DOCKER_COMPOSE ps | grep -q "Up"; then echo "💾 Data storage: $(pwd)/data" echo "" echo "🔧 Useful commands (run from $(pwd)):" - echo " $DOCKER_COMPOSE logs -f # View logs" - echo " $DOCKER_COMPOSE stop # Stop Capsule" - echo " $DOCKER_COMPOSE restart # Restart Capsule" - echo " $DOCKER_COMPOSE down # Stop and remove" + echo " $CONTAINER_COMPOSE logs -f # View logs" + echo " $CONTAINER_COMPOSE stop # Stop Capsule" + echo " $CONTAINER_COMPOSE restart # Restart Capsule" + echo " $CONTAINER_COMPOSE down # Stop and remove" echo "" echo "📚 Documentation:" echo " • README.md - Getting started guide" @@ -180,7 +192,7 @@ else echo "❌ Container failed to start" echo "" echo "Troubleshooting:" - echo "1. Check logs: $DOCKER_COMPOSE logs" + echo "1. Check logs: $CONTAINER_COMPOSE logs" echo "2. Verify .env file has ENCRYPTION_KEY set" echo "3. Check if port 7654 is available" echo "" diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 0000000..1d97144 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactCompiler: true, +}; + +export default nextConfig; diff --git a/next.config.ts b/next.config.ts deleted file mode 100644 index 66e1566..0000000 --- a/next.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ - reactCompiler: true, -}; - -export default nextConfig;