Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Build and Push pktHub Docker Image

on:
push:
branches:
- feature/docker
- main

jobs:
build-and-push:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write # Required to push to ghcr.io

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/pkthub
tags: |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=raw,value=latest-dev,enable=${{ github.ref != 'refs/heads/main' }}
type=sha,format=short

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker-container # Required for GHA cache backend

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./pktHub # Repo root is pktSolution; app lives in pktHub/
file: ./pktHub/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
60 changes: 60 additions & 0 deletions pktHub/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Python virtual environment
venv/
.venv/

# Node modules and frontend build output
# (the Dockerfile build stage handles node_modules inside the build container)
frontend/node_modules/
frontend/dist/

# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd
*.pdb
.Python

# Database files (data lives on the volume, not in the image)
*.db
*.db-wal
*.db-shm
*.sqlite

# Runtime config (generated by entrypoint from env vars)
config.yaml

# Logs and backups
logs/
backups/

# Git
.git/
.gitignore
.gitattributes

# Local dev overrides
*.bak_*
_*.py

# systemd service file (not needed in container)
*.service

# IDE / OS
.vscode/
.idea/
*.DS_Store
Thumbs.db

# Test artifacts
.pytest_cache/
htmlcov/
.coverage

# Docker files themselves (avoid recursive inclusion)
Dockerfile
docker-compose*.yml
.dockerignore
.env
.env.*
!.env.example
41 changes: 41 additions & 0 deletions pktHub/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# ─────────────────────────────────────────────────────────────
# pktHub — Environment Variables
#
# Copy this file to .env and fill in your values:
# cp .env.example .env
#
# .env is NOT committed to version control (.gitignore excludes it).
# ─────────────────────────────────────────────────────────────

# ── Required ──────────────────────────────────────────────────
# Admin password for the initial user created on first start.
# Must be set — the container will refuse to start without it.
APP_ADMIN_PASSWORD=change_me_immediately

# ── Optional ──────────────────────────────────────────────────

# Initial admin username (default: admin)
APP_ADMIN_USER=admin

# Initial admin email (default: admin@localhost)
APP_ADMIN_EMAIL=admin@localhost

# HTTP port (default: 80)
APP_HTTP_PORT=80

# HTTPS port (default: 443)
APP_HTTPS_PORT=443

# JWT signing secret.
# If blank, a random secret is generated on first start and stored in
# /data/config.yaml on the persistent volume.
# Set a fixed value here to keep user sessions valid across container
# recreations and image updates.
# Generate one with: openssl rand -hex 32
APP_JWT_SECRET=

# ── Okta / OIDC SSO (optional) ────────────────────────────────
# Leave all three blank to disable SSO and use local auth only.
OKTA_DOMAIN=
OKTA_CLIENT_ID=
OKTA_CLIENT_SECRET=
56 changes: 56 additions & 0 deletions pktHub/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ─────────────────────────────────────────────
# Stage 1 — Build React/Vite frontend
# ─────────────────────────────────────────────
FROM node:18-alpine AS frontend-builder

WORKDIR /build

COPY frontend/package*.json ./
RUN npm ci --silent

COPY frontend/ ./
RUN npm run build


# ─────────────────────────────────────────────
# Stage 2 — Runtime image
# ─────────────────────────────────────────────
FROM python:3.11-slim

# System dependencies: openssl for cert generation, supervisor for process management
RUN apt-get update && apt-get install -y --no-install-recommends \
openssl \
supervisor \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Application code
COPY app/ ./app/

# Frontend build output from Stage 1
COPY --from=frontend-builder /build/dist ./frontend/dist/

# Entrypoint script
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# /data is the persistent volume mount point:
# /data/config.yaml — generated from env vars on first start
# /data/pkthub.db — SQLite database
# /data/ssl/ — TLS certificate and key
# /data/logs/ — application logs
# /data/backups/ — database backups
VOLUME ["/data"]

# Default ports — override with APP_HTTP_PORT / APP_HTTPS_PORT env vars
EXPOSE 80 443

# Point the app at the volume-backed config
ENV PKTSUITE_CONFIG=/data/config.yaml

ENTRYPOINT ["/entrypoint.sh"]
Loading
Loading