chore: add Docker config files and fix fail2ban bind mount path
This commit is contained in:
49
.containerignore
Normal file
49
.containerignore
Normal file
@@ -0,0 +1,49 @@
|
||||
# ──────────────────────────────────────────────
|
||||
# BanGUI — .dockerignore / .containerignore
|
||||
# Works with both Docker and Podman.
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
venv
|
||||
env
|
||||
|
||||
# IDE / editor
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Python caches
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
.mypy_cache
|
||||
.ruff_cache
|
||||
.pytest_cache
|
||||
.coverage
|
||||
htmlcov
|
||||
|
||||
# Node
|
||||
frontend/node_modules
|
||||
frontend/.vite
|
||||
|
||||
# Build artifacts
|
||||
dist
|
||||
build
|
||||
*.egg-info
|
||||
|
||||
# Documentation (keep README at root if needed)
|
||||
Docs
|
||||
|
||||
# Tests (not needed in production images)
|
||||
backend/tests
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
49
.dockerignore
Normal file
49
.dockerignore
Normal file
@@ -0,0 +1,49 @@
|
||||
# ──────────────────────────────────────────────
|
||||
# BanGUI — .dockerignore / .containerignore
|
||||
# Works with both Docker and Podman.
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
venv
|
||||
env
|
||||
|
||||
# IDE / editor
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Python caches
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
.mypy_cache
|
||||
.ruff_cache
|
||||
.pytest_cache
|
||||
.coverage
|
||||
htmlcov
|
||||
|
||||
# Node
|
||||
frontend/node_modules
|
||||
frontend/.vite
|
||||
|
||||
# Build artifacts
|
||||
dist
|
||||
build
|
||||
*.egg-info
|
||||
|
||||
# Documentation (keep README at root if needed)
|
||||
Docs
|
||||
|
||||
# Tests (not needed in production images)
|
||||
backend/tests
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
69
Docker/Dockerfile.backend
Normal file
69
Docker/Dockerfile.backend
Normal file
@@ -0,0 +1,69 @@
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# BanGUI — Backend image (Python / FastAPI)
|
||||
#
|
||||
# Compatible with Docker and Podman.
|
||||
# Build context must be the project root.
|
||||
#
|
||||
# Usage:
|
||||
# docker build -t bangui-backend -f Docker/Dockerfile.backend .
|
||||
# podman build -t bangui-backend -f Docker/Dockerfile.backend .
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
# ── Stage 1: build dependencies ──────────────────────────────
|
||||
FROM python:3.12-slim AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Install build-time system dependencies
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends gcc libffi-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY backend/pyproject.toml /build/
|
||||
|
||||
# Install Python dependencies into a virtual-env so we can copy it cleanly
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
RUN pip install --no-cache-dir --upgrade pip \
|
||||
&& pip install --no-cache-dir .
|
||||
|
||||
# ── Stage 2: runtime image ───────────────────────────────────
|
||||
FROM python:3.12-slim AS runtime
|
||||
|
||||
LABEL maintainer="BanGUI" \
|
||||
description="BanGUI backend — fail2ban web management API"
|
||||
|
||||
# Non-root user for security
|
||||
RUN groupadd --gid 1000 bangui \
|
||||
&& useradd --uid 1000 --gid bangui --shell /bin/bash --create-home bangui
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the pre-built virtual-env
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH" \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
# Copy application source
|
||||
COPY backend/app /app/app
|
||||
COPY fail2ban-master /app/fail2ban-master
|
||||
|
||||
# Data directory for the SQLite database
|
||||
RUN mkdir -p /data && chown bangui:bangui /data
|
||||
VOLUME ["/data"]
|
||||
|
||||
# Default environment values (override at runtime)
|
||||
ENV BANGUI_DATABASE_PATH="/data/bangui.db" \
|
||||
BANGUI_FAIL2BAN_SOCKET="/var/run/fail2ban/fail2ban.sock" \
|
||||
BANGUI_LOG_LEVEL="info"
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
USER bangui
|
||||
|
||||
# Health-check using the built-in health endpoint
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')" || exit 1
|
||||
|
||||
CMD ["uvicorn", "app.main:create_app", "--factory", "--host", "0.0.0.0", "--port", "8000"]
|
||||
45
Docker/Dockerfile.frontend
Normal file
45
Docker/Dockerfile.frontend
Normal file
@@ -0,0 +1,45 @@
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# BanGUI — Frontend image (React / Vite → nginx)
|
||||
#
|
||||
# Compatible with Docker and Podman.
|
||||
# Build context must be the project root.
|
||||
#
|
||||
# Usage:
|
||||
# docker build -t bangui-frontend -f Docker/Dockerfile.frontend .
|
||||
# podman build -t bangui-frontend -f Docker/Dockerfile.frontend .
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
# ── Stage 1: install & build ─────────────────────────────────
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Install dependencies first (layer caching)
|
||||
COPY frontend/package.json frontend/package-lock.json* /build/
|
||||
RUN npm ci --ignore-scripts
|
||||
|
||||
# Copy source and build
|
||||
COPY frontend/ /build/
|
||||
RUN npm run build
|
||||
|
||||
# ── Stage 2: serve with nginx ────────────────────────────────
|
||||
FROM nginx:1.27-alpine AS runtime
|
||||
|
||||
LABEL maintainer="BanGUI" \
|
||||
description="BanGUI frontend — fail2ban web management UI"
|
||||
|
||||
# Remove default nginx content
|
||||
RUN rm -rf /usr/share/nginx/html/*
|
||||
|
||||
# Copy built assets
|
||||
COPY --from=builder /build/dist /usr/share/nginx/html
|
||||
|
||||
# Custom nginx config for SPA routing + API reverse proxy
|
||||
COPY Docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||
CMD wget -qO /dev/null http://localhost:80/ || exit 1
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -31,7 +31,7 @@ services:
|
||||
PUID: 0
|
||||
PGID: 0
|
||||
volumes:
|
||||
- fail2ban-dev-config:/config
|
||||
- ./fail2ban-dev-config:/config
|
||||
- fail2ban-dev-run:/var/run/fail2ban
|
||||
- /var/log:/var/log:ro
|
||||
healthcheck:
|
||||
|
||||
102
Docker/compose.prod.yml
Normal file
102
Docker/compose.prod.yml
Normal file
@@ -0,0 +1,102 @@
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# BanGUI — Production Compose
|
||||
#
|
||||
# Compatible with:
|
||||
# docker compose -f Docker/compose.prod.yml up -d
|
||||
# podman compose -f Docker/compose.prod.yml up -d
|
||||
# podman-compose -f Docker/compose.prod.yml up -d
|
||||
#
|
||||
# Prerequisites:
|
||||
# Create a .env file at the project root (or pass --env-file):
|
||||
# BANGUI_SESSION_SECRET=<random-secret>
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
name: bangui
|
||||
|
||||
services:
|
||||
# ── fail2ban ─────────────────────────────────────────────────
|
||||
fail2ban:
|
||||
image: lscr.io/linuxserver/fail2ban:latest
|
||||
container_name: bangui-fail2ban
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
network_mode: host
|
||||
environment:
|
||||
TZ: "${BANGUI_TIMEZONE:-UTC}"
|
||||
PUID: 0
|
||||
PGID: 0
|
||||
volumes:
|
||||
- fail2ban-config:/config
|
||||
- fail2ban-run:/var/run/fail2ban
|
||||
- /var/log:/var/log:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "fail2ban-client", "ping"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 15s
|
||||
retries: 3
|
||||
|
||||
# ── Backend (FastAPI + uvicorn) ─────────────────────────────
|
||||
backend:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Docker/Dockerfile.backend
|
||||
container_name: bangui-backend
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
fail2ban:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
BANGUI_DATABASE_PATH: "/data/bangui.db"
|
||||
BANGUI_FAIL2BAN_SOCKET: "/var/run/fail2ban/fail2ban.sock"
|
||||
BANGUI_LOG_LEVEL: "info"
|
||||
BANGUI_SESSION_SECRET: "${BANGUI_SESSION_SECRET:?Set BANGUI_SESSION_SECRET}"
|
||||
BANGUI_TIMEZONE: "${BANGUI_TIMEZONE:-UTC}"
|
||||
volumes:
|
||||
- bangui-data:/data
|
||||
- fail2ban-run:/var/run/fail2ban:ro
|
||||
expose:
|
||||
- "8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- bangui-net
|
||||
|
||||
# ── Frontend (nginx serving built SPA + API proxy) ──────────
|
||||
frontend:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Docker/Dockerfile.frontend
|
||||
container_name: bangui-frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${BANGUI_PORT:-8080}:80"
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:80/"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 5s
|
||||
retries: 3
|
||||
networks:
|
||||
- bangui-net
|
||||
|
||||
volumes:
|
||||
bangui-data:
|
||||
driver: local
|
||||
fail2ban-config:
|
||||
driver: local
|
||||
fail2ban-run:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
bangui-net:
|
||||
driver: bridge
|
||||
34
Docker/nginx.conf
Normal file
34
Docker/nginx.conf
Normal file
@@ -0,0 +1,34 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# ── Gzip compression ─────────────────────────────────────
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
gzip_min_length 256;
|
||||
|
||||
# ── API reverse proxy → backend container ─────────────────
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000;
|
||||
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;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# ── Static assets with long-term caching ──────────────────
|
||||
location /assets/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# ── SPA fallback — serve index.html for client routes ─────
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
106
Docker/push.sh
Normal file
106
Docker/push.sh
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build and push BanGUI container images to the Gitea registry.
|
||||
#
|
||||
# Usage:
|
||||
# ./push.sh # builds & pushes with tag "latest"
|
||||
# ./push.sh v1.2.3 # builds & pushes with tag "v1.2.3"
|
||||
# ./push.sh v1.2.3 --no-build # pushes existing images only
|
||||
#
|
||||
# Prerequisites:
|
||||
# podman login git.lpl-mind.de (or: docker login git.lpl-mind.de)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
REGISTRY="git.lpl-mind.de"
|
||||
NAMESPACE="lukas.pupkalipinski"
|
||||
PROJECT="bangui"
|
||||
|
||||
BACKEND_IMAGE="${REGISTRY}/${NAMESPACE}/${PROJECT}/backend"
|
||||
FRONTEND_IMAGE="${REGISTRY}/${NAMESPACE}/${PROJECT}/frontend"
|
||||
|
||||
TAG="${1:-latest}"
|
||||
SKIP_BUILD=false
|
||||
if [[ "${2:-}" == "--no-build" ]]; then
|
||||
SKIP_BUILD=true
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
log() { echo -e "\n>>> $*"; }
|
||||
err() { echo -e "\nERROR: $*" >&2; exit 1; }
|
||||
|
||||
# Detect container engine (podman preferred, docker fallback)
|
||||
if command -v podman &>/dev/null; then
|
||||
ENGINE="podman"
|
||||
elif command -v docker &>/dev/null; then
|
||||
ENGINE="docker"
|
||||
else
|
||||
err "Neither podman nor docker is installed."
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pre-flight checks
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "============================================"
|
||||
echo " BanGUI — Build & Push"
|
||||
echo " Engine : ${ENGINE}"
|
||||
echo " Registry : ${REGISTRY}"
|
||||
echo " Tag : ${TAG}"
|
||||
echo "============================================"
|
||||
|
||||
if [[ "${ENGINE}" == "podman" ]]; then
|
||||
if ! podman login --get-login "${REGISTRY}" &>/dev/null; then
|
||||
err "Not logged in. Run:\n podman login ${REGISTRY}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ "${SKIP_BUILD}" == false ]]; then
|
||||
log "Building backend image → ${BACKEND_IMAGE}:${TAG}"
|
||||
"${ENGINE}" build \
|
||||
-t "${BACKEND_IMAGE}:${TAG}" \
|
||||
-f "${SCRIPT_DIR}/Dockerfile.backend" \
|
||||
"${PROJECT_ROOT}"
|
||||
|
||||
log "Building frontend image → ${FRONTEND_IMAGE}:${TAG}"
|
||||
"${ENGINE}" build \
|
||||
-t "${FRONTEND_IMAGE}:${TAG}" \
|
||||
-f "${SCRIPT_DIR}/Dockerfile.frontend" \
|
||||
"${PROJECT_ROOT}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Push
|
||||
# ---------------------------------------------------------------------------
|
||||
log "Pushing ${BACKEND_IMAGE}:${TAG}"
|
||||
"${ENGINE}" push "${BACKEND_IMAGE}:${TAG}"
|
||||
|
||||
log "Pushing ${FRONTEND_IMAGE}:${TAG}"
|
||||
"${ENGINE}" push "${FRONTEND_IMAGE}:${TAG}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Summary
|
||||
# ---------------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Push complete!"
|
||||
echo ""
|
||||
echo " Images:"
|
||||
echo " ${BACKEND_IMAGE}:${TAG}"
|
||||
echo " ${FRONTEND_IMAGE}:${TAG}"
|
||||
echo ""
|
||||
echo " Deploy on server:"
|
||||
echo " ${ENGINE} login ${REGISTRY}"
|
||||
echo " ${ENGINE} compose -f Docker/compose.prod.yml pull"
|
||||
echo " ${ENGINE} compose -f Docker/compose.prod.yml up -d"
|
||||
echo "============================================"
|
||||
1
Docs/test.md
Normal file
1
Docs/test.md
Normal file
@@ -0,0 +1 @@
|
||||
https://lists.blocklist.de/lists/all.txt
|
||||
Reference in New Issue
Block a user