From 45fd382b134fee2e320d8da6dcddb1dc14a96275 Mon Sep 17 00:00:00 2001 From: HueByte Date: Sun, 22 Feb 2026 18:12:06 +0100 Subject: [PATCH] feat: add Docker support with environment configuration and entrypoint script --- .env.example | 39 +++++++ docker-compose.yml | 8 +- docs/articles/docker.md | 130 ++++++++++++++++++++++++ docs/articles/getting-started.md | 11 ++ docs/articles/toc.yml | 2 + src/EchoHub.Server/Dockerfile | 4 +- src/EchoHub.Server/docker-entrypoint.sh | 10 ++ 7 files changed, 197 insertions(+), 7 deletions(-) create mode 100644 .env.example create mode 100644 docs/articles/docker.md create mode 100644 src/EchoHub.Server/docker-entrypoint.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..749bb9b --- /dev/null +++ b/.env.example @@ -0,0 +1,39 @@ +# EchoHub Server Configuration +# Copy this file to .env and customize as needed: cp .env.example .env +# These override appsettings.json via ASP.NET Core's configuration hierarchy. + +# ── Server ─────────────────────────────────────────────────────────── +Server__Name=My EchoHub Server +Server__Description=A self-hosted EchoHub chat server +Server__PublicServer=false +# Server__PublicHost=echohub.example.com +# Server__Admins__0=adminUsername + +# ── JWT ────────────────────────────────────────────────────────────── +# Auto-generated on first run if left empty. Only set if you need a stable secret across containers. +# Jwt__Secret= +# Jwt__Issuer=EchoHub.Server +# Jwt__Audience=EchoHub.Client + +# ── Encryption ─────────────────────────────────────────────────────── +# Auto-generated on first run if left empty. +# Encryption__Key= +# Encryption__EncryptDatabase=false + +# ── Storage ────────────────────────────────────────────────────────── +# Defaults are set in the Dockerfile to use /app/data for persistence. +# Storage__CleanupIntervalHours=1 +# Storage__RetentionDays=30 + +# ── IRC Gateway ────────────────────────────────────────────────────── +Irc__Enabled=false +# Irc__Port=6667 +# Irc__TlsEnabled=false +# Irc__TlsPort=6697 +# Irc__TlsCertPath= +# Irc__TlsCertPassword= +# Irc__ServerName=echohub +# Irc__Motd=Welcome to EchoHub IRC Gateway! + +# ── Logging ────────────────────────────────────────────────────────── +# Serilog__MinimumLevel__Default=Information diff --git a/docker-compose.yml b/docker-compose.yml index 8135ebc..ca887c1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,12 +12,8 @@ services: # - "6697:6697" # IRC (TLS encrypted, preferred) volumes: - echohub-data:/app/data - environment: - - Server__Name=My EchoHub Server - - Server__Description=A self-hosted EchoHub chat server - # - Server__PublicServer=true - # - Server__PublicHost=echohub.example.com - # - Irc__Enabled=true + env_file: + - .env volumes: echohub-data: diff --git a/docs/articles/docker.md b/docs/articles/docker.md new file mode 100644 index 0000000..7eaaa19 --- /dev/null +++ b/docs/articles/docker.md @@ -0,0 +1,130 @@ +# Docker + +## Quick Start + +```bash +cp .env.example .env # create your config +docker compose up -d # start the server +``` + +On first run the server automatically generates JWT and encryption keys, creates the database, and seeds a `#general` channel. Connect with the EchoHub client to `http://localhost:5000`. + +### Using a Pre-built Image + +Instead of building locally, you can pull from GHCR. In `docker-compose.yml`, replace the `build` block: + +```yaml +services: + echohub-server: + image: ghcr.io/huebyte/echohub-server:latest + # build: + # context: ./src + # dockerfile: EchoHub.Server/Dockerfile +``` + +## Configuration + +All settings are configured through the `.env` file. These are ASP.NET Core environment variables that override `appsettings.json`. + +| Variable | Default | Description | +|---|---|---| +| `Server__Name` | My EchoHub Server | Display name for your server | +| `Server__Description` | A self-hosted EchoHub chat server | Server description | +| `Server__PublicServer` | `false` | List on the [public directory](https://echohub.voidcube.cloud/servers) | +| `Server__PublicHost` | *(empty)* | Public address for the directory listing | +| `Server__Admins__0` | *(empty)* | Admin username (use `__1`, `__2` for more) | +| `Jwt__Secret` | *(auto-generated)* | JWT signing key. Auto-generated on first run | +| `Encryption__Key` | *(auto-generated)* | AES encryption key. Auto-generated on first run | +| `Encryption__EncryptDatabase` | `false` | Encrypt message content in the database | +| `Storage__CleanupIntervalHours` | `1` | How often to clean expired uploads | +| `Storage__RetentionDays` | `30` | Days to keep uploaded files | +| `Irc__Enabled` | `false` | Enable the IRC gateway | +| `Irc__Port` | `6667` | IRC plain-text port | +| `Irc__TlsEnabled` | `false` | Enable IRC over TLS | +| `Irc__TlsPort` | `6697` | IRC TLS port | +| `Irc__ServerName` | `echohub` | IRC server name shown to clients | +| `Irc__Motd` | Welcome to EchoHub IRC Gateway! | Message of the day | +| `Serilog__MinimumLevel__Default` | `Information` | Log level (`Debug`, `Warning`, etc.) | + +## Persistent Data + +All server state lives in a single Docker volume mounted at `/app/data`: + +``` +/app/data/ +├── appsettings.json # generated config with JWT/encryption keys +├── echohub.db # SQLite database +├── uploads/ # uploaded files and avatars +└── logs/ # rolling log files (14-day retention) +``` + +### Backup + +```bash +# stop the server to ensure a consistent snapshot +docker compose stop +# copy the data volume to a local directory +docker cp echohub-server:/app/data ./backup +docker compose start +``` + +## IRC Gateway + +To enable IRC, set these in your `.env`: + +```env +Irc__Enabled=true +``` + +Then uncomment the port in `docker-compose.yml`: + +```yaml +ports: + - "5000:5000" + - "6697:6697" # IRC (TLS encrypted, preferred) +``` + +For TLS, also set: + +```env +Irc__TlsEnabled=true +Irc__TlsCertPath=/app/data/cert.pfx +Irc__TlsCertPassword=your_password +``` + +Mount your certificate into the data volume or bind-mount it directly. + +IRC users must have an existing EchoHub account. See [Getting Started](getting-started.md#connect-via-irc) for client connection examples. + +## Updating + +```bash +# if using pre-built images +docker compose pull +docker compose up -d + +# if building locally +docker compose build +docker compose up -d +``` + +Data persists across updates since it lives in the named volume. + +## Troubleshooting + +**Port already in use** -- Another process is using port 5000. Change the host port in `docker-compose.yml`: + +```yaml +ports: + - "8080:5000" # access via http://localhost:8080 +``` + +**Permission denied on volume** -- The container runs as a non-root `echohub` user (UID 999). If using bind mounts instead of named volumes, ensure the directory is writable. + +**View logs** -- Check the container output: + +```bash +docker compose logs -f echohub-server +``` + +File-based logs are also available inside the volume at `/app/data/logs/`. diff --git a/docs/articles/getting-started.md b/docs/articles/getting-started.md index 2d45cad..7b7bba3 100644 --- a/docs/articles/getting-started.md +++ b/docs/articles/getting-started.md @@ -6,6 +6,17 @@ Or grab a self-contained binary from [Releases](https://github.com/HueByte/EchoHub/releases) -- no runtime needed. +## Docker + +The quickest way to host a server: + +```bash +cp .env.example .env +docker compose up -d +``` + +See the [Docker guide](docker.md) for configuration, pre-built images, and more. + ## Run the Server ```bash diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index 814359c..b371d95 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -1,5 +1,7 @@ - name: Getting Started href: getting-started.md +- name: Docker + href: docker.md - name: Architecture href: architecture.md - name: Encryption diff --git a/src/EchoHub.Server/Dockerfile b/src/EchoHub.Server/Dockerfile index 2a71380..c4b94a9 100644 --- a/src/EchoHub.Server/Dockerfile +++ b/src/EchoHub.Server/Dockerfile @@ -23,6 +23,8 @@ RUN groupadd -r echohub && useradd -r -g echohub -d /app echohub \ && chown -R echohub:echohub /app COPY --from=build --chown=echohub:echohub /app/publish . +COPY --chown=echohub:echohub EchoHub.Server/docker-entrypoint.sh /app/docker-entrypoint.sh +RUN chmod +x /app/docker-entrypoint.sh USER echohub @@ -34,4 +36,4 @@ ENV ASPNETCORE_ENVIRONMENT=Production \ EXPOSE 5000 6667 6697 -ENTRYPOINT ["dotnet", "EchoHub.Server.dll"] +ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/src/EchoHub.Server/docker-entrypoint.sh b/src/EchoHub.Server/docker-entrypoint.sh new file mode 100644 index 0000000..902c86d --- /dev/null +++ b/src/EchoHub.Server/docker-entrypoint.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Persist appsettings.json in the data volume so auto-generated keys +# (JWT secret, encryption key) survive container recreation. +if [ ! -f /app/data/appsettings.json ]; then + cp /app/appsettings.example.json /app/data/appsettings.json +fi +ln -sf /app/data/appsettings.json /app/appsettings.json + +exec dotnet EchoHub.Server.dll