@twinsearth/w2m-dsh-plugin 0.0.0-stage → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1288 -0
- package/LICENSE +21 -0
- package/PROTOCOL-v0.1.2.md +165 -0
- package/PROTOCOL-v0.3.0.md +454 -0
- package/PROTOCOL-v0.3.9.md +207 -0
- package/PROTOCOL-v0.4.0.md +255 -0
- package/PROTOCOL.md +339 -0
- package/README.md +665 -2
- package/bin/w2m-localside.mjs +303 -0
- package/bin/w2m-rabbit.mjs +396 -0
- package/bin/w2m-stun.mjs +231 -0
- package/cordis.patch.yml +94 -0
- package/deploy/caddy/Caddyfile.example +118 -0
- package/deploy/docker/Dockerfile +144 -0
- package/deploy/docker/README.md +338 -0
- package/deploy/docker/docker-compose.yml +179 -0
- package/deploy/nginx/w2m.conf.example +196 -0
- package/deploy/shared-server/README.md +118 -0
- package/deploy/shared-server/install.sh +255 -0
- package/deploy/systemd/w2m-rabbit.service +150 -0
- package/deploy/systemd/w2m-stun.service +69 -0
- package/deploy/windows/README.md +115 -0
- package/deploy/windows/install-service.ps1 +195 -0
- package/deploy/windows/w2m-agent-supervisor.mjs +205 -0
- package/deploy/windows/winsw/w2m-localside.xml +50 -0
- package/docs/DEPLOY.md +902 -0
- package/docs/LINT-AUDIT.md +492 -0
- package/docs/PIPELINE-DESIGN.md +95 -0
- package/docs/TROUBLESHOOTING.md +560 -0
- package/docs/UI-CARDS.md +81 -0
- package/lib/index.js +13 -0
- package/lib/tools.js +11 -0
- package/package.json +133 -4
- package/src/agent/agent.mjs +3317 -0
- package/src/agent/allowed-commands.mjs +116 -0
- package/src/agent/caps.mjs +437 -0
- package/src/agent/exec.mjs +356 -0
- package/src/agent/git.mjs +616 -0
- package/src/agent/identity.mjs +253 -0
- package/src/agent/p2p-node.mjs +1243 -0
- package/src/agent/p2p.mjs +605 -0
- package/src/agent/resolve.mjs +148 -0
- package/src/agent/spool.mjs +252 -0
- package/src/agent/stun.mjs +397 -0
- package/src/agent/url.mjs +127 -0
- package/src/plugin/auto-update.mjs +574 -0
- package/src/plugin/schedule.mjs +452 -0
- package/src/plugin/shared-config.mjs +264 -0
- package/src/plugin/tools.mjs +3891 -0
- package/src/plugin/update-install.mjs +764 -0
- package/src/plugin/update-source.mjs +686 -0
- package/src/relay/metrics.mjs +284 -0
- package/src/relay/peers.mjs +180 -0
- package/src/relay/persistence.mjs +207 -0
- package/src/relay/report.mjs +591 -0
- package/src/relay/server.mjs +1187 -0
- package/src/relay/state.mjs +2004 -0
- package/src/relay/stun-server.mjs +733 -0
- package/src/signing.mjs +359 -0
- package/src/util/cli.mjs +70 -0
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# This file is the bundle patch declared by package.json's `dsh.bundle.patch`.
|
|
2
|
+
# It mounts the plugin explicitly at `./tools` rather than relying on a
|
|
3
|
+
# "root export is the plugin" convention, so reading this file tells you which
|
|
4
|
+
# module of the package becomes the plugin.
|
|
5
|
+
#
|
|
6
|
+
# ---------------------------------------------------------------------------
|
|
7
|
+
# Why this is an `insert:` list and not a bare `- id: w2m`
|
|
8
|
+
# ---------------------------------------------------------------------------
|
|
9
|
+
# A bare `- id: w2m` entry is a *non-insert* patch: it replaces fields on an
|
|
10
|
+
# entry that an earlier layer already created. No earlier layer creates `w2m`,
|
|
11
|
+
# so the Loader reports
|
|
12
|
+
#
|
|
13
|
+
# dsh: [@twinsearth/w2m-dsh-plugin] patch: entry "w2m" not found
|
|
14
|
+
#
|
|
15
|
+
# and skips it. Measured with DSH 0.2.0-rc.2 (`--dump-config-schema`, $defs.patch):
|
|
16
|
+
#
|
|
17
|
+
# "An insert appends entries, optionally inside the group identified by id.
|
|
18
|
+
# Other patches replace supplied fields; ... Unknown targets and non-insert
|
|
19
|
+
# patches without a nonempty id are warned and skipped."
|
|
20
|
+
#
|
|
21
|
+
# The consequence of the old shape was silent: `dsh plugin add` succeeded, the
|
|
22
|
+
# profile listed the bundle, DSH started cleanly -- and **no `w2m` row was ever
|
|
23
|
+
# composed**, so none of the eight tools existed. `--dump-config` showed 183 rows
|
|
24
|
+
# and zero of them named this package.
|
|
25
|
+
#
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
# Configuring the relay URL, and the direct path (v0.4.0)
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# The relay URL has a default as of v0.4.0: the shared W2M server, which hosts the
|
|
30
|
+
# relay, a STUN server and a reverse proxy on one address. Leaving `rabbitUrl` empty
|
|
31
|
+
# therefore means "use the shared server", not "guess" -- and `w2m_status` reports
|
|
32
|
+
# `rabbit_source: "shared-default"` with a note naming the address, so a machine
|
|
33
|
+
# talking to somebody else's host can never be a surprise.
|
|
34
|
+
#
|
|
35
|
+
# The order is `rabbitUrl` -> `W2M_RABBIT_URL` -> the shared server, and an explicit
|
|
36
|
+
# value always wins. Set one of the first two to run against your own relay:
|
|
37
|
+
#
|
|
38
|
+
# - id: w2m
|
|
39
|
+
# config:
|
|
40
|
+
# rabbitUrl: https://w2m.example.com # may include a sub-path
|
|
41
|
+
# operatorToken: !!js process.env.W2M_OPERATOR_TOKEN
|
|
42
|
+
# stateDir: !!js (process.env.DSH_HOME + '/xclient')
|
|
43
|
+
#
|
|
44
|
+
# `operatorToken` is the credential that authorises *sending* instructions. It is
|
|
45
|
+
# separate from the per-machine device token on purpose: a machine that can receive
|
|
46
|
+
# work should not automatically be able to command the others. The relay writes it to
|
|
47
|
+
# <state>/operator-token.txt on first start and prints it once.
|
|
48
|
+
#
|
|
49
|
+
# `p2pMode` decides how a dispatched offer travels, and it is the release's headline
|
|
50
|
+
# switch, so every value is validated at load and a typo is refused rather than
|
|
51
|
+
# defaulted:
|
|
52
|
+
#
|
|
53
|
+
# auto (default) punch the direct path and push the offer over it; the relay's
|
|
54
|
+
# own offer on the SSE stream stays as the fallback, so a failed punch is
|
|
55
|
+
# invisible to the caller except in `direct_pushes` and each machine's
|
|
56
|
+
# `transport`. This is what `W2M_P2P_MODE` unset gives you.
|
|
57
|
+
# direct the same push, but a failed punch is not hidden: the executor refuses an
|
|
58
|
+
# offer that did not arrive over the direct path
|
|
59
|
+
# (`refusal_reason: P2P_UNAVAILABLE`), so a fleet that must use the fast
|
|
60
|
+
# path fails loudly instead of quietly falling back.
|
|
61
|
+
# relay no UDP socket is bound at all and nothing is dialled -- exactly v0.3.9's
|
|
62
|
+
# behaviour. Use it to take the direct path out of the picture entirely
|
|
63
|
+
# while diagnosing something else.
|
|
64
|
+
#
|
|
65
|
+
# - id: w2m
|
|
66
|
+
# config:
|
|
67
|
+
# p2pMode: relay # or W2M_P2P_MODE=relay
|
|
68
|
+
#
|
|
69
|
+
# `stunServers` is the list used to discover the address a peer can reach this machine
|
|
70
|
+
# on. Unset means the shared server first, then three public fallbacks -- the shared
|
|
71
|
+
# server is asked first on purpose, because a machine that can reach the relay can
|
|
72
|
+
# reach that STUN server, so the address it reports is measured over the same path the
|
|
73
|
+
# punch will use. Naming servers replaces that list, so give the shared one explicitly
|
|
74
|
+
# if you still want the relay's own path measured:
|
|
75
|
+
#
|
|
76
|
+
# - id: w2m
|
|
77
|
+
# config:
|
|
78
|
+
# stunServers: ['202.182.123.154:3478', 'stun.example.com:3478']
|
|
79
|
+
# # or W2M_STUN_SERVERS=a:3478,b:3478
|
|
80
|
+
#
|
|
81
|
+
# A loopback punch (both machines on one host) exercises the code path and says nothing
|
|
82
|
+
# about NAT traversal; `w2m_status` reports the measured NAT mapping so the difference
|
|
83
|
+
# is visible rather than assumed.
|
|
84
|
+
- insert:
|
|
85
|
+
- id: w2m
|
|
86
|
+
name: '@twinsearth/w2m-dsh-plugin/tools'
|
|
87
|
+
config:
|
|
88
|
+
rabbitUrl: ''
|
|
89
|
+
operatorToken: ''
|
|
90
|
+
autoStartAgent: false
|
|
91
|
+
machineName: ''
|
|
92
|
+
allowedCommands: []
|
|
93
|
+
p2pMode: auto
|
|
94
|
+
stunServers: []
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# W2M relay behind Caddy -- example configuration
|
|
3
|
+
# ============================================================================
|
|
4
|
+
#
|
|
5
|
+
# This file is a TEMPLATE. Replace every <placeholder> before using it.
|
|
6
|
+
#
|
|
7
|
+
# Validated how: caddy is not installed on the authoring machine, so this file
|
|
8
|
+
# was NOT checked with `caddy validate`. Run that on the server before
|
|
9
|
+
# reloading -- docs/DEPLOY.md gives the exact commands.
|
|
10
|
+
#
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
# WHY CADDY NEEDS ONE EXPLICIT SETTING FOR SSE
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# Caddy 2 enables automatic HTTPS (issuance + renewal) with no extra
|
|
15
|
+
# configuration, which is its main advantage over nginx here. It also buffers
|
|
16
|
+
# responses by default, like nginx -- but unlike nginx it does NOT honour the
|
|
17
|
+
# relay's `X-Accel-Buffering: no` header, because that header is an
|
|
18
|
+
# nginx-specific convention.
|
|
19
|
+
#
|
|
20
|
+
# So the setting that matters is:
|
|
21
|
+
#
|
|
22
|
+
# flush_interval -1
|
|
23
|
+
#
|
|
24
|
+
# Without it the browser connects to /v1/stream, receives no events, and the
|
|
25
|
+
# UI looks "connected but dead" -- the same failure `proxy_buffering off`
|
|
26
|
+
# prevents under nginx.
|
|
27
|
+
#
|
|
28
|
+
# Caddy handles HTTP/1.1 and HTTP/2 correctly by itself, so the other two
|
|
29
|
+
# nginx-side SSE requirements have no Caddy equivalent.
|
|
30
|
+
#
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
# SHAPE 1: served at the root of a dedicated hostname (recommended).
|
|
33
|
+
# Replace <your-domain> with a name whose A/AAAA record points at this server.
|
|
34
|
+
# Relay flags: no --base-path, no --tls-cert/--tls-key (Caddy terminates TLS).
|
|
35
|
+
# ============================================================================
|
|
36
|
+
|
|
37
|
+
<your-domain> {
|
|
38
|
+
# ---- the event stream: this route alone needs flush_interval ----------
|
|
39
|
+
@stream path /v1/stream
|
|
40
|
+
handle @stream {
|
|
41
|
+
reverse_proxy 127.0.0.1:8787 {
|
|
42
|
+
# Disable response buffering: frames must reach the client as
|
|
43
|
+
# they are written. This is the Caddy equivalent of nginx's
|
|
44
|
+
# `proxy_buffering off`, and it is the single most important
|
|
45
|
+
# line in this file.
|
|
46
|
+
flush_interval -1
|
|
47
|
+
|
|
48
|
+
# The stream is long-lived and quiet between the relay's 15s
|
|
49
|
+
# keepalive comments, so let it stay open indefinitely.
|
|
50
|
+
transport http {
|
|
51
|
+
read_timeout 0
|
|
52
|
+
write_timeout 0
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# ---- health check, unauthenticated on purpose -------------------------
|
|
58
|
+
handle /healthz {
|
|
59
|
+
reverse_proxy 127.0.0.1:8787
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# ---- everything else --------------------------------------------------
|
|
63
|
+
handle {
|
|
64
|
+
reverse_proxy 127.0.0.1:8787 {
|
|
65
|
+
flush_interval -1
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# ---- logging ----------------------------------------------------------
|
|
70
|
+
# Off by default in Caddy. Turn it on while bringing a deployment up: it is
|
|
71
|
+
# the fastest way to see whether a client reached /v1/stream, and whether
|
|
72
|
+
# Caddy itself (not the relay) answered 401/403/404.
|
|
73
|
+
log {
|
|
74
|
+
output file /var/log/caddy/w2m-access.log {
|
|
75
|
+
roll_size 10MiB
|
|
76
|
+
roll_keep 5
|
|
77
|
+
}
|
|
78
|
+
format json
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# ============================================================================
|
|
83
|
+
# SHAPE 2: served under a sub-path, e.g. https://<your-domain>/w2m/
|
|
84
|
+
# ============================================================================
|
|
85
|
+
# Uncomment and adapt when the relay must share a hostname with something else.
|
|
86
|
+
#
|
|
87
|
+
# Start the relay with `--base-path /w2m` and forward the prefix UNCHANGED.
|
|
88
|
+
# Caddy's `handle_path` strips the prefix -- using it here is the classic
|
|
89
|
+
# mistake and produces 404 on every /v1/* call. `handle` preserves the path.
|
|
90
|
+
#
|
|
91
|
+
# Client `rabbitUrl` must carry the same prefix:
|
|
92
|
+
# https://<your-domain>/w2m
|
|
93
|
+
# ============================================================================
|
|
94
|
+
|
|
95
|
+
# <your-domain> {
|
|
96
|
+
# @stream path /w2m/v1/stream
|
|
97
|
+
# handle @stream {
|
|
98
|
+
# reverse_proxy 127.0.0.1:8787 {
|
|
99
|
+
# flush_interval -1
|
|
100
|
+
# transport http {
|
|
101
|
+
# read_timeout 0
|
|
102
|
+
# write_timeout 0
|
|
103
|
+
# }
|
|
104
|
+
# }
|
|
105
|
+
# }
|
|
106
|
+
#
|
|
107
|
+
# # The relay answers /healthz both with and without the prefix, so a probe
|
|
108
|
+
# # on either path keeps working; this keeps the bare one reachable.
|
|
109
|
+
# handle /healthz {
|
|
110
|
+
# reverse_proxy 127.0.0.1:8787
|
|
111
|
+
# }
|
|
112
|
+
#
|
|
113
|
+
# handle /w2m/* {
|
|
114
|
+
# reverse_proxy 127.0.0.1:8787 {
|
|
115
|
+
# flush_interval -1
|
|
116
|
+
# }
|
|
117
|
+
# }
|
|
118
|
+
# }
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# W2M relay (Rabbit) — multi-architecture container image
|
|
3
|
+
# ============================================================================
|
|
4
|
+
#
|
|
5
|
+
# Build from the repository root (the COPY paths are relative to the context):
|
|
6
|
+
#
|
|
7
|
+
# docker build -f deploy/docker/Dockerfile -t w2m-relay:0.3.4 .
|
|
8
|
+
#
|
|
9
|
+
# Multi-arch, without needing the target hardware:
|
|
10
|
+
#
|
|
11
|
+
# docker buildx build --platform linux/amd64,linux/arm64 \
|
|
12
|
+
# -f deploy/docker/Dockerfile -t w2m-relay:0.3.4 .
|
|
13
|
+
#
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# ZERO RUNTIME DEPENDENCIES — this is the reason the image is so small
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
# The relay declares `"dependencies": {}` and genuinely has none. Its complete
|
|
18
|
+
# import closure is 7 files / ~175 KiB and resolves to exactly seven node:
|
|
19
|
+
# builtins:
|
|
20
|
+
#
|
|
21
|
+
# bin/w2m-rabbit.mjs -> src/relay/server.mjs, src/util/cli.mjs
|
|
22
|
+
# src/relay/server.mjs -> state.mjs, persistence.mjs, report.mjs, ../signing.mjs
|
|
23
|
+
# src/relay/{state,report,persistence}.mjs -> state.mjs
|
|
24
|
+
# builtins: node:crypto node:fs node:http node:https node:os node:path node:util
|
|
25
|
+
#
|
|
26
|
+
# Therefore **no package manager runs in this image** — there is no `npm
|
|
27
|
+
# install`, no `npm ci`, no lockfile to go stale and no registry access at
|
|
28
|
+
# build time. If a future change needs an npm package, that would break a core
|
|
29
|
+
# project promise and should be raised, not added here.
|
|
30
|
+
#
|
|
31
|
+
# `lib/` is deliberately absent: it is the DSH *plugin* entry
|
|
32
|
+
# (`package.json` "main": "lib/index.js") and the relay CLI never imports it.
|
|
33
|
+
# `cordis.patch.yml` is likewise plugin-host configuration, not relay runtime.
|
|
34
|
+
#
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
# PINNING
|
|
37
|
+
# ---------------------------------------------------------------------------
|
|
38
|
+
# The base tag is pinned to an exact patch release, not `22` or `latest`: a
|
|
39
|
+
# floating tag makes two builds of the same commit produce different images.
|
|
40
|
+
#
|
|
41
|
+
# `node:22.23.3-bookworm-slim` is the current 22.x LTS line (v22.23.3 released
|
|
42
|
+
# 2026-09-23, verified against https://nodejs.org/dist/index.json). The *tag's
|
|
43
|
+
# existence in the registry* could not be checked from the authoring machine —
|
|
44
|
+
# see deploy/docker/README.md, "What was verified".
|
|
45
|
+
#
|
|
46
|
+
# For byte-for-byte reproducibility, pin the digest instead. Resolve it with:
|
|
47
|
+
# docker buildx imagetools inspect node:22.23.3-bookworm-slim
|
|
48
|
+
# and replace the FROM line with `node:22.23.3-bookworm-slim@sha256:<digest>`.
|
|
49
|
+
# Note a digest names ONE platform, so a multi-arch build needs the per-arch
|
|
50
|
+
# digests from the manifest list.
|
|
51
|
+
# ============================================================================
|
|
52
|
+
|
|
53
|
+
FROM node:22.23.3-bookworm-slim
|
|
54
|
+
|
|
55
|
+
# Fixed uid/gid so a bind-mounted state directory has predictable ownership on
|
|
56
|
+
# the host (a random uid would make `ls -l` on the host meaningless).
|
|
57
|
+
ARG W2M_UID=10001
|
|
58
|
+
ARG W2M_GID=10001
|
|
59
|
+
|
|
60
|
+
# `production` keeps any transitive tooling quiet and is honest about intent:
|
|
61
|
+
# nothing in this image is a dev dependency.
|
|
62
|
+
ENV NODE_ENV=production
|
|
63
|
+
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
# Runtime payload — exactly the import closure above, nothing else.
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
WORKDIR /app
|
|
68
|
+
|
|
69
|
+
# `--chown` takes the numeric uid/gid, which is portable (BuildKit and the
|
|
70
|
+
# classic builder both accept it) and avoids a separate `RUN chown -R /app`
|
|
71
|
+
# layer that would duplicate every file's bytes.
|
|
72
|
+
COPY --chown=10001:10001 bin/w2m-rabbit.mjs /app/bin/w2m-rabbit.mjs
|
|
73
|
+
COPY --chown=10001:10001 src/relay/ /app/src/relay/
|
|
74
|
+
COPY --chown=10001:10001 src/util/ /app/src/util/
|
|
75
|
+
COPY --chown=10001:10001 src/signing.mjs /app/src/signing.mjs
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# Unprivileged user
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
# The uid/gid above are pinned by ARG, so keep the numbers in the COPY lines
|
|
81
|
+
# equal to the defaults here. (Docker cannot interpolate an ARG inside --chown,
|
|
82
|
+
# so if you change W2M_UID/W2M_GID you must change these four lines too.)
|
|
83
|
+
RUN groupadd --gid "${W2M_GID}" w2m \
|
|
84
|
+
&& useradd --uid "${W2M_UID}" --gid "${W2M_GID}" --no-create-home --shell /usr/sbin/nologin w2m \
|
|
85
|
+
&& mkdir -p /var/lib/w2m \
|
|
86
|
+
&& chown "${W2M_UID}:${W2M_GID}" /var/lib/w2m
|
|
87
|
+
|
|
88
|
+
USER w2m
|
|
89
|
+
|
|
90
|
+
# ---------------------------------------------------------------------------
|
|
91
|
+
# State
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
93
|
+
# devices.json (device tokens), ledger.jsonl (task ledger) and
|
|
94
|
+
# operator-token.txt (0600) live here. Losing this volume means every paired
|
|
95
|
+
# machine must pair again, so it is a VOLUME rather than image content.
|
|
96
|
+
#
|
|
97
|
+
# /var/lib/w2m is also the relay's $HOME, which is where it falls back to
|
|
98
|
+
# `$HOME/.dsh/xclient/rabbit` when `--state` is not given — so the volume covers
|
|
99
|
+
# the default and the explicit path alike.
|
|
100
|
+
ENV HOME=/var/lib/w2m
|
|
101
|
+
VOLUME ["/var/lib/w2m"]
|
|
102
|
+
|
|
103
|
+
EXPOSE 8787
|
|
104
|
+
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
# Health check
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
# GET /healthz needs NO credential, which is exactly why it is the right probe
|
|
109
|
+
# here: the container must be able to report itself healthy without holding the
|
|
110
|
+
# operator token (that token authorises SENDING work and must not leak into
|
|
111
|
+
# image configuration).
|
|
112
|
+
#
|
|
113
|
+
# `node -e` is used instead of curl/wget so the image needs no extra packages —
|
|
114
|
+
# keeping the "install nothing" property intact through the health check too.
|
|
115
|
+
#
|
|
116
|
+
# The probe is deliberately hard-coded to 8787. The container's listen port is
|
|
117
|
+
# fixed at 8787 and the *host* port is what varies (see docker-compose.yml), so
|
|
118
|
+
# this probe never needs to change. If you override the command's --port, you
|
|
119
|
+
# must override this HEALTHCHECK to match.
|
|
120
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
|
121
|
+
CMD ["node", "-e", "fetch('http://127.0.0.1:8787/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# How it starts
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
# `--host 0.0.0.0` is correct HERE and only here. Inside a container the loopback
|
|
127
|
+
# interface is unreachable from outside its network namespace, so a loopback
|
|
128
|
+
# bind would make the published port useless. Exposure is controlled by the port
|
|
129
|
+
# *mapping* instead — docker-compose.yml binds 127.0.0.1 on the host by default,
|
|
130
|
+
# so nothing is published to the outside world until the operator says so.
|
|
131
|
+
#
|
|
132
|
+
# TLS terminates in front of this container (nginx/Caddy on the host, or a
|
|
133
|
+
# tunnel), which is why the default invocation carries no --tls-cert/--tls-key:
|
|
134
|
+
# the relay behind a proxy speaks plain HTTP over a loopback-only VPS hop.
|
|
135
|
+
# `--trust-proxy` is NOT in the default command on purpose — turn it on only
|
|
136
|
+
# when a proxy you control really is in front, because with it on the relay
|
|
137
|
+
# believes X-Forwarded-For and a directly-reachable client could forge its
|
|
138
|
+
# address past the pairing rate limit.
|
|
139
|
+
#
|
|
140
|
+
# Add flags per deployment shape, e.g. behind nginx/Caddy:
|
|
141
|
+
# docker run ... w2m-relay:0.3.4 --host 0.0.0.0 --port 8787 \
|
|
142
|
+
# --state /var/lib/w2m --trust-proxy
|
|
143
|
+
ENTRYPOINT ["node", "/app/bin/w2m-rabbit.mjs"]
|
|
144
|
+
CMD ["--host", "0.0.0.0", "--port", "8787", "--state", "/var/lib/w2m"]
|