Docker: full Dockerized deployment (volumes, host networking, multi-package-manager build)

- docker-compose.yml: network_mode host so 127.0.0.1 refs (.env) keep working;
  mounts /var/www/Gamedata + write volumes; /api/health healthcheck; mem_limit
- Dockerfile: package-manager detection (pnpm/yarn/npm) + PACKAGE_MANAGER arg;
  runs as www-data (UID/GID 33) so gamedata is writable; .env loaded only for
  the build (no secrets baked in); build runs on the host network
- .dockerignore: .env stays in the build context (needed for NEXT_PUBLIC_*)
- README: Docker deployment section (paths, volumes, chown, migrations on host)
This commit is contained in:
openhands committed 2026-09-02 12:25:42 +02:00
1 parent 58c35a2920
commit cb927db78d
4 files changed
+360 -394

No files matched your search

+6 -2
View File
@@ -7,8 +7,12 @@ storage
prod.log prod.log
update.log update.log
.pm2 .pm2
.env # NOTE: .env is intentionally NOT ignored here — the build loads it (only inside
# a build RUN layer) to produce NEXT_PUBLIC_* + validated build-time values.
# It is not copied into the runtime image (the runner stage copies only
# .next/standalone, public/, and .next/static).
# .env
*.tsbuildinfo *.tsbuildinfo
# ~3GB client assets; mounted as a volume at runtime (see docker-compose.yml) # Runtime write targets; bound as RW volumes at runtime (see docker-compose.yml)
public/nitro-assets public/nitro-assets
public/swf public/swf
+65 -24
View File
File diff suppressed because it is too large. Load diff
+237 -359
View File
File diff suppressed because it is too large. Load diff
+52 -9
View File
@@ -1,20 +1,63 @@
version: "3.8"
services: services:
cms: cms:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
# The host disables Docker iptables (daemon.json: "iptables": false), so
# build containers on the bridge network have no outbound NAT/DNS. Build on
# the host network instead so pnpm/npm/yarn can reach the registry.
network: host
args:
# Run as the host owner (www-data = UID/GID 33, already present in the
# node base image) of /var/www/Gamedata so the container can read + write
# the shared gamedata directory.
RUN_USER: "www-data"
container_name: epicnext-cms container_name: epicnext-cms
ports: # Runs on the host network so existing 127.0.0.1 refs in .env keep working:
# Host port -> container port (container always listens on 3002) # MariaDB (3306), DragonflyDB/Redis (6379), emulator RCON (3003) + API (3001),
- "3002:3002" # and the imaging renderer (8082). The container then listens directly on the
# host's 3002 (the same port the current host-side CMS uses).
# NOTE: stop the host CMS (next-server on 3002) first, otherwise the port is taken.
network_mode: host
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
volumes: volumes:
# ~3GB client assets live on the host; mount them read-only into the container # ── Write targets (runtime imports/uploads, persistent on the host) ──
- ./public/nitro-assets:/app/public/nitro-assets:ro # The CMS writes imported furni/figures/pets/effects here (see
- ./public/swf:/app/public/swf:ro # src/lib/services/furni-asset-dirs.ts). These must be RW, and owned by
# Runtime uploaded media (persistent on the host) # UID/GID 33 (www-data) on the host so the container user can write to them:
# sudo chown -R 33:33 ./public/nitro-assets ./public/swf ./storage
- ./public/nitro-assets:/app/public/nitro-assets
- ./public/swf:/app/public/swf
# Runtime uploaded media (persistent on the host).
- ./storage:/app/storage - ./storage:/app/storage
# ── Shared gamedata (absolute path the CMS hardcodes & writes to) ──
# src/lib/services/furni-asset-dirs.ts: `DEFAULT_GAMEDATA_ROOT =
# /var/www/Gamedata`. nginx on the host also serves /gamedata/ from this
# same directory, so mount it into the container at the same absolute path.
# Must be RW so furniture/badge imports can write mirrors to it.
- /var/www/Gamedata:/var/www/Gamedata
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3002/api/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mem_limit: 2g
# ── Opt-in: Octane-Renderer (Habbo avatar imager) ──
# Serves /imaging on port 3030 (the CMS proxies /imaging to it). Renders
# avatars into /var/www/Gamedata/habbo-imaging, so it needs RW access.
# Disabled by default — uncomment to run the renderer as a container.
# imager:
# build:
# context: /var/www/Octane-Renderer
# container_name: epicnext-octane-renderer
# ports:
# - "3030:3030"
# restart: unless-stopped
# volumes:
# - /var/www/Gamedata:/var/www/Gamedata