Files
image/README.md
T

5.0 KiB

Shared image repository

icons/ is served as /image/icons/. General portraits follow these rules:

  • icons/장수/<장수명>.<확장자> is the canonical shared path.
  • Scenario-specific collections keep a separate directory such as icons/걸그룹/ or icons/롤시나리오/.
  • Root-level numeric files such as icons/1047.jpg are compatibility aliases for deployed legacy versions. Do not delete or replace them while those versions are in service.
  • A general name must map to one canonical file. If two records intentionally need different portraits, disambiguate the scenario name or use an explicit scenario-specific path.

The core2026 repository owns resources/general-icons.json and tools/manage-general-icons.mjs. Use that tool with this repository as --image-root to synchronize aliases, scenario paths, and verify that every catalog source exists and has identical bytes.

Public URLs

The same tracked files are exposed through both URL contracts:

  • https://sam.hided.net/image/game/... and /image/icons/...
  • https://sam-image.hided.net/game/... and /icons/...
  • https://sam-image.hided.net/image/... is a compatibility alias.

Do not redirect the old /image/* URLs to the dedicated domain. Existing PHP and core2026 clients use same-origin relative paths and can move independently. The image server never exposes the repository root, .git, PHP sources, or directory listings.

Node webhook deployment service

compose.yaml runs a read-only Nginx static edge and an internal Node service. Only the edge publishes port 8191. The Node service verifies the raw Gitea X-Gitea-Signature, accepts push events for devsam/image, fetches the exact remote branch tip, rejects dirty or non-fast-forward updates, and serializes all Git changes. The initial and only allowed branch is master unless IMAGE_ALLOWED_BRANCHES is explicitly expanded.

The current Caddy host reaches this server from 172.30.1.75. Keep the observed source in the untracked .env; re-check it whenever Caddy networking changes. The published port binds all server interfaces, so production also needs a host DOCKER-USER (or equivalent) firewall rule allowing that source CIDR to TCP 8191 and rejecting other sources. Nginx applies the same source allowlist.

Prepare

cp .env.example .env
./deploy/scripts/init-secrets.sh
docker compose config --quiet
docker compose build

Apply and inspect the dedicated Docker ingress chain with root privileges:

sudo env CADDY_SOURCE_CIDR=172.30.1.75/32 IMAGE_PORT=8191 \
  ./deploy/scripts/firewall-8191.sh apply
sudo ./deploy/scripts/firewall-8191.sh check

The script only owns the SAM_IMAGE_INGRESS chain and its port-8191 jump from DOCKER-USER; it does not flush shared firewall chains.

Secret values are generated under ignored secrets/ files with mode 0600 and are never printed. Put the contents of secrets/gitea_webhook_secret into the Gitea webhook configuration. Configure a JSON push webhook targeting:

https://sam-image.hided.net/v1/hooks/gitea

Use branch filter master. Disable the old PHP webhook before enabling the new writer. The legacy PHP files remain in hook/ for an explicit rollback, but PHP and Node must never mutate the checkout concurrently.

Legacy HTTP mutation is disabled by default. An emergency PHP rollback must first stop image-hook, then create the ignored hook/legacy-enabled sentinel in the legacy checkout before restoring its Caddy/Gitea route. Remove the sentinel before Node is started again. CLI execution of hook/git_pull.php from the hook/ directory remains available for local recovery without exposing the HTTP endpoint.

Start and verify

docker compose up -d --build
docker compose ps
curl -fsS https://sam-image.hided.net/healthz
curl -fsS https://sam-image.hided.net/v1/status
curl -fsS https://sam-image.hided.net/game/back.jpg -o /dev/null
curl -fsS https://sam-image.hided.net/image/icons/default.jpg -o /dev/null

Nginx serves only game/, icons/, hook/list.json, and hook/inventory.v2.json. The API inventory additionally reports the deployed branch, full commit, generation time, asset list, and both public base URLs.

Explicit branch deployment

Automatic pushes only update the active branch. Add a branch to IMAGE_ALLOWED_BRANCHES, recreate image-hook, and switch it with the internal signed administration command:

./deploy/scripts/admin-deploy.sh <branch> [expected-commit]

The administration route is not proxied through Nginx or Caddy.

Tests and rollback

docker build -t sam-image-hook:test node-hook
docker run --rm sam-image-hook:test npm test
docker compose exec -T image-web nginx -t -c /tmp/nginx.conf

Stopping image-hook does not remove the last checked-out files from the static service. For a full rollback, stop Node mutation first, restore the old Caddy/PHP webhook route, and only then enable the legacy writer. Preserve both checkouts until public file hashes and representative browser requests have been verified.