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.
This commit is contained in:
37
.env.docker.example
Normal file
37
.env.docker.example
Normal 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
2
.gitignore
vendored
@@ -46,6 +46,8 @@ build/
|
|||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
!.env.docker.example
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# Ignore SQLite runtime files
|
# Ignore SQLite runtime files
|
||||||
bot/db/**/*.db-journal
|
bot/db/**/*.db-journal
|
||||||
|
|||||||
19
DOCKER.md
Normal file
19
DOCKER.md
Normal 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
19
bot/.dockerignore
Normal 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
29
bot/Dockerfile
Normal 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
11
dashboard/.dockerignore
Normal 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
44
dashboard/Dockerfile
Normal 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"]
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
output: "standalone",
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
output: "standalone",
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
|
|||||||
99
docker-compose.yml
Normal file
99
docker-compose.yml
Normal 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:
|
||||||
Reference in New Issue
Block a user