Docker and Portainer Deploy - wickedyoda/Glinet_discord_bot GitHub Wiki
Deployment guide for local Docker Compose, Portainer stacks, and proxy-fronted production setups.
- Variation A: Local development on localhost bind.
- Variation B: Container behind reverse proxy (recommended production).
- Variation C: Portainer stack with direct
environment:variables. - Variation D: Prebuilt image deployment (no local build context).
services:
discord_invite_bot:
build:
context: .
container_name: discord_role_bot
env_file:
- .env
environment:
- WEB_BIND_HOST=0.0.0.0
- WEB_ENABLED=${WEB_ENABLED:-true}
- WEB_PORT=${WEB_PORT:-8080}
- WEB_HTTP_PUBLISH=${WEB_HTTP_PUBLISH:-8080}
- WEB_HTTPS_ENABLED=${WEB_HTTPS_ENABLED:-true}
- WEB_HTTPS_PORT=${WEB_HTTPS_PORT:-8081}
- WEB_HTTPS_PUBLISH=${WEB_HTTPS_PUBLISH:-8081}
- LOG_DIR=${LOG_DIR:-/logs}
- LOG_HARDEN_FILE_PERMISSIONS=${LOG_HARDEN_FILE_PERMISSIONS:-true}
- LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-90}
- LOG_ROTATION_INTERVAL_DAYS=${LOG_ROTATION_INTERVAL_DAYS:-1}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- CONTAINER_LOG_LEVEL=${CONTAINER_LOG_LEVEL:-ERROR}
- WEB_PUBLIC_BASE_URL=${WEB_PUBLIC_BASE_URL:-}
- WEB_SSL_DIR=${WEB_SSL_DIR:-/app/data/ssl}
- WEB_SSL_CERT_FILE=${WEB_SSL_CERT_FILE:-tls.crt}
- WEB_SSL_KEY_FILE=${WEB_SSL_KEY_FILE:-tls.key}
- WEB_SSL_COMMON_NAME=${WEB_SSL_COMMON_NAME:-localhost}
- WEB_TRUST_PROXY_HEADERS=${WEB_TRUST_PROXY_HEADERS:-true}
- WEB_SESSION_COOKIE_SECURE=${WEB_SESSION_COOKIE_SECURE:-true}
- WEB_ENFORCE_CSRF=${WEB_ENFORCE_CSRF:-true}
- WEB_ENFORCE_SAME_ORIGIN_POSTS=${WEB_ENFORCE_SAME_ORIGIN_POSTS:-true}
ports:
- "${WEB_HTTP_PUBLISH:-8080}:${WEB_PORT:-8080}"
- "${WEB_HTTPS_PUBLISH:-8081}:${WEB_HTTPS_PORT:-8081}"
volumes:
- ./data:/app/data
- ./logs:/logs
- ./.env:/app/.env
restart: unless-stoppedRun:
docker compose up -d --buildRecommended adjustments:
- Keep container port private (localhost bind or internal network only).
- Set
WEB_PUBLIC_BASE_URL=https://discord-admin.example.com/. - Keep
WEB_SESSION_COOKIE_SECURE=true. - Keep CSRF and same-origin checks enabled.
- The bot can also listen on built-in HTTPS
8081; it generates a self-signed cert in${DATA_DIR}/ssl/if none exists.
Example host mapping:
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:8081:8081"Equivalent .env values for same-host reverse proxy only:
WEB_HTTP_PUBLISH=127.0.0.1:8080
WEB_HTTPS_PUBLISH=127.0.0.1:8081If your reverse proxy is on another machine, leave the publish override disabled or set it to the Docker host's private LAN IP:
# Disabled explicit host/IP pinning:
# WEB_HTTP_PUBLISH=8080
# WEB_HTTPS_PUBLISH=8081
# Explicit private LAN bind:
# WEB_HTTP_PUBLISH=192.168.1.50:8080
# WEB_HTTPS_PUBLISH=192.168.1.50:8081Use your proxy to publish HTTPS domain externally and restrict those ports with a firewall.
When Portainer cannot access local .env path:
- Remove
env_file:reference - Provide variables under
environment:directly
Example image:
ghcr.io/wickedyoda/discord_invite_bot:latest
Recommended web settings persistence:
- keep the source
.envmounted read-only - set
WEB_ENV_FILE=/app/data/web-settings.env - let the web GUI write only that writable file inside
/app/data
Recommended persistent volume:
/root/docker/linkbot/data:/app/data
Use prebuilt image when:
- build context is unavailable
- Dockerfile is not present in stack path
- you want predictable immutable deployments
Supported deployment model:
- GHCR published images are pushed as a single multi-arch manifest list:
linux/amd64linux/arm64
- Docker automatically pulls the correct architecture image for the host.
Local multi-arch build (Buildx):
docker buildx create --use --name glinet-multiarch-builder
docker buildx inspect --bootstrap
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/<owner>/discord_invite_bot:local-multiarch \
--push \
.Notes:
- Use
--pushfor true multi-arch output;--loadonly loads a single architecture into the local Docker engine. - Standard
docker compose buildstays host-native and is still the fastest local test path.
- App listens on
WEB_PORTinside container. - Host publish override controlled by
WEB_HTTP_PUBLISH/WEB_HTTPS_PUBLISH. - Public exposure should happen via reverse proxy, not direct open port.
Persistent log files:
-
${LOG_DIR}/bot.log(application logs, default/logs/bot.log) -
${LOG_DIR}/bot_log.log(bot channel payload mirror, default/logs/bot_log.log) -
${LOG_DIR}/container_errors.log(error stream used by/logs, default/logs/container_errors.log) -
${LOG_DIR}/web_gui_audit.log(web admin interaction audit stream, default/logs/web_gui_audit.log)
Tune with:
LOG_LEVELCONTAINER_LOG_LEVELLOG_DIR-
LOG_HARDEN_FILE_PERMISSIONS(recommendedtrue, enforces0700log directory and0600log files where supported) -
LOG_RETENTION_DAYS(default90) -
LOG_ROTATION_INTERVAL_DAYS(default1)
- Pull latest image or code.
- Review
.env/compose changes. - Recreate container:
docker compose up -d --build
- Check logs:
docker compose logs -f discord_invite_bot
-
env file ... not found:- Replace
env_filewith explicitenvironmentvalues in Portainer.
- Replace
-
failed to read dockerfile:- Use image-based deploy or correct stack path.
- Web UI unavailable:
- Check host bind address, host port mapping, and proxy upstream target.
- Avoid exposing container port directly to internet.
- Use HTTPS proxy + HSTS + strict forwarding headers.
- Keep secrets only in trusted env/secret management tooling.