Enhance project configuration by setting output to "standalone" in Next.js config files and updating .gitignore to include example environment files for better clarity and management.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 9s

This commit is contained in:
TheOnlyMace
2026-07-21 17:35:08 +02:00
parent b4110c3d66
commit 41d5841d82
10 changed files with 262 additions and 0 deletions

37
.env.docker.example Normal file
View File

@@ -0,0 +1,37 @@
# ── Docker Compose (.env) — copy to .env in the repo root ─────────────────────
# cp .env.docker.example .env
# Discord Bot
TOKEN=TOKEN_HERE
brand_name=HexaHost
OWNER_IDS=YOUR_DISCORD_USER_ID_HERE
DASHBOARD_ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
# Shared secret — must match between bot API and dashboard
DASHBOARD_API_KEY=generate_a_long_random_secret_here
# Lavalink (optional music)
LAVALINK_HOST=lavalink.jirayu.net
LAVALINK_PASSWORD=youshallnotpass
LAVALINK_SECURE=false
LAVALINK_PORT=13592
EMOJI_SYNC=false
JISHAKU_ENABLED=false
# Traefik (optional override — default in compose: letsencrypt)
# TRAEFIK_CERT_RESOLVER=letsencrypt
# ── Dashboard / NextAuth ──────────────────────────────────────────────────────
NEXTAUTH_SECRET=generate_a_long_random_secret_here
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
# Same Discord user IDs as owners/admins (comma-separated)
ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
NEXT_PUBLIC_ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
NEXT_PUBLIC_BRAND_NAME=HexaHost
NEXT_PUBLIC_BRAND_NAME_WORD=HH
# Discord OAuth Redirect URL in the Discord Developer Portal:
# https://bot.hexahost.de/api/auth/callback/discord

2
.gitignore vendored
View File

@@ -46,6 +46,8 @@ build/
.env
.env.local
.env.*.local
!.env.docker.example
!.env.example
# Ignore SQLite runtime files
bot/db/**/*.db-journal

19
DOCKER.md Normal file
View File

@@ -0,0 +1,19 @@
# Docker
Copy `.env.docker.example` to `.env`, fill in secrets, then:
```bash
docker network create traefik-network # only if it does not exist yet
docker compose up -d --build
```
| Service | Container | Exposure |
|---------|-----------|----------|
| Bot + FastAPI | `hexahost-bot` | Internal (`bot:8000`) — Discord Gateway outbound |
| Dashboard | `hexahost-dashboard` | Traefik → `https://bot.hexahost.de` |
Data volumes: `bot-db`, `bot-jsondb`, `bot-logs`.
Discord OAuth redirect: `https://bot.hexahost.de/api/auth/callback/discord`
If your Traefik cert resolver is not named `letsencrypt`, set `TRAEFIK_CERT_RESOLVER` in `.env`. Entrypoints expected: `web` (80) and `websecure` (443).

19
bot/.dockerignore Normal file
View File

@@ -0,0 +1,19 @@
.env
.env.*
!.env.example
__pycache__
*.py[cod]
*.db
*.db-journal
.venv
venv
myenv
.git
.gitignore
*.md
LICENSE
logs
*.log
.pytest_cache
.mypy_cache
CodeX.py

29
bot/Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
# HexaHost Discord Bot + FastAPI dashboard backend
FROM python:3.12-slim-bookworm
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libffi-dev \
libjpeg62-turbo-dev \
zlib1g-dev \
libsodium-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Persist SQLite / JSON data outside the image
RUN mkdir -p /app/db /app/jsondb /app/logs
EXPOSE 8000
CMD ["python", "HexaHost.py"]

11
dashboard/.dockerignore Normal file
View File

@@ -0,0 +1,11 @@
.env
.env.*
!.env.example
node_modules
.next
.git
.gitignore
*.md
LICENSE
npm-debug.log*
.eslintrc.json

44
dashboard/Dockerfile Normal file
View File

@@ -0,0 +1,44 @@
# HexaHost Dashboard (Next.js)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build-time public env (overridden at runtime where possible)
ARG NEXT_PUBLIC_BRAND_NAME=HexaHost
ARG NEXT_PUBLIC_BRAND_NAME_WORD=HH
ARG NEXT_PUBLIC_ADMIN_IDS=
ARG NEXT_PUBLIC_API_URL=
ENV NEXT_TELEMETRY_DISABLED=1 \
NEXT_PUBLIC_BRAND_NAME=$NEXT_PUBLIC_BRAND_NAME \
NEXT_PUBLIC_BRAND_NAME_WORD=$NEXT_PUBLIC_BRAND_NAME_WORD \
NEXT_PUBLIC_ADMIN_IDS=$NEXT_PUBLIC_ADMIN_IDS \
NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
RUN mkdir -p public && npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=3000 \
HOSTNAME=0.0.0.0
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]

View File

@@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
images: {
remotePatterns: [
{

View File

@@ -1,6 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
output: "standalone",
images: {
remotePatterns: [
{

99
docker-compose.yml Normal file
View File

@@ -0,0 +1,99 @@
# HexaHost — Bot + Dashboard behind Traefik
#
# Prerequisites:
# - External Docker network: traefik-network
# - Traefik already running and attached to that network
# - Copy .env.docker.example → .env and fill secrets
#
# Start:
# docker compose up -d --build
name: hexahost
services:
bot:
build:
context: ./bot
dockerfile: Dockerfile
container_name: hexahost-bot
restart: unless-stopped
env_file:
- .env
environment:
API_ENABLED: "true"
API_HOST: "0.0.0.0"
API_PORT: "8000"
TUNNEL_ENABLED: "false"
CORS_ORIGINS: "https://bot.hexahost.de"
volumes:
- bot-db:/app/db
- bot-jsondb:/app/jsondb
- bot-logs:/app/logs
networks:
- traefik-network
- hexahost-internal
healthcheck:
test:
[
"CMD",
"python",
"-c",
"import socket; s=socket.create_connection(('127.0.0.1',8000),5); s.close()",
]
interval: 30s
timeout: 10s
retries: 5
start_period: 90s
dashboard:
build:
context: ./dashboard
dockerfile: Dockerfile
args:
NEXT_PUBLIC_BRAND_NAME: ${NEXT_PUBLIC_BRAND_NAME:-HexaHost}
NEXT_PUBLIC_BRAND_NAME_WORD: ${NEXT_PUBLIC_BRAND_NAME_WORD:-HH}
NEXT_PUBLIC_ADMIN_IDS: ${NEXT_PUBLIC_ADMIN_IDS:-}
container_name: hexahost-dashboard
restart: unless-stopped
depends_on:
bot:
condition: service_started
env_file:
- .env
environment:
# Server-side proxy → Bot API (Docker-intern, nicht öffentlich)
DASHBOARD_API_URL: http://bot:8000/api/v1
NEXTAUTH_URL: https://bot.hexahost.de/
NEXT_PUBLIC_BRAND_NAME: ${NEXT_PUBLIC_BRAND_NAME:-HexaHost}
NEXT_PUBLIC_BRAND_NAME_WORD: ${NEXT_PUBLIC_BRAND_NAME_WORD:-HH}
PORT: "3000"
HOSTNAME: "0.0.0.0"
networks:
- traefik-network
- hexahost-internal
labels:
- traefik.enable=true
- traefik.docker.network=traefik-network
# HTTP → HTTPS redirect (optional, falls Entrypoint "web" existiert)
- traefik.http.routers.hexahost-dashboard-http.rule=Host(`bot.hexahost.de`)
- traefik.http.routers.hexahost-dashboard-http.entrypoints=web
- traefik.http.routers.hexahost-dashboard-http.middlewares=hexahost-https-redirect
- traefik.http.middlewares.hexahost-https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.hexahost-https-redirect.redirectscheme.permanent=true
# HTTPS
- traefik.http.routers.hexahost-dashboard.rule=Host(`bot.hexahost.de`)
- traefik.http.routers.hexahost-dashboard.entrypoints=websecure
- traefik.http.routers.hexahost-dashboard.tls=true
- traefik.http.routers.hexahost-dashboard.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}
- traefik.http.services.hexahost-dashboard.loadbalancer.server.port=3000
networks:
traefik-network:
external: true
hexahost-internal:
driver: bridge
volumes:
bot-db:
bot-jsondb:
bot-logs: