Commit Graph
12 Commits
Author SHA1 Message Date
bitdeals 1f9452b773 feat: generate XFF_HMAC_KEY when none is passed
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 37s
An empty key switches the pseudonym off: no X-Client-Id is sent, and a
rate limit downstream falls back to one bucket shared by every visitor.
That is the one state nobody chooses on purpose and the easiest to reach
by forgetting a line in a .env — so the entrypoint now fills the key in
with `openssl rand -base64 32` when nothing else did.

Nobody picks this value, nothing outside the container needs to know it,
and no two deployments need the same one, which is what makes generating
it the right default rather than a convenience. A fresh key per container
start costs a reset of the downstream rate-limit buckets — invisible
against a one-minute window — and makes pseudonyms from before and after
unlinkable, which is the property the key exists for rather than a loss.
Passing one explicitly still wins, for whoever wants pseudonyms stable
across restarts or identical on two proxies.

base64 and not hex, deliberately: HAProxy's hmac() decodes the key as
base64, and hex would be accepted and silently decoded into something
else — a usable key, but it would quietly cost the guarantee that a
malformed one stops the container at configuration parsing.

The base image's entrypoint is the haproxy binary with no shell in
between, so the wrapper is the whole chain and execs the same binary with
the same arguments. CMD is restated rather than inherited.

Verified by building the image and checking the config in all three
states: unset (wrapper reports it generated one, config parses), set and
valid (wrapper silent, config parses), set and not base64 (`[ALERT]
invalid args in converter 'hmac' : failed to parse key`, container
refuses to start).

READMEs updated in both languages, and "address" is spelled "IP address"
throughout — it was never anything else.
2026-08-10 14:50:57 +00:00
bitdeals c063688b75 ci: pass the registry password on stdin, fail on a failed push
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 44s
A password in argv is world-readable through /proc/PID/cmdline while the
command runs; docker warns about it for that reason. The environment of a
process is readable by its owner alone, so $PASS itself was never the problem.

The two pushes are joined with && rather than left as separate statements: the
step's exit code is the last command's, so the intent is now explicit instead
of resting on whatever -e flag the runner's shell happens to carry.
2026-08-07 13:38:54 +00:00
bitdeals a66944077d docs: add README in English and Russian
Same structure as the bitmessage and bitcoind repositories: intro, usage with
compose and cli examples, a parameter table, and notes carrying the traps —
why the certificate must exist before start-up, why the runtime API is a unix
socket, why there are two loggers, and why HSTS is one day rather than a year.
2026-08-07 13:38:54 +00:00
bitdeals ab75b21cb4 feat: harden the edge and move the runtime API off TCP
The runtime API was an unauthenticated `level admin` channel on TCP 9999.
`expose:` restricts nothing and docker networks have no per-port rules, so it
was reachable by every container sharing a network — nginx included — and
reaching it means installing your own certificate and key. It is now a unix
socket on a volume shared with certbot alone, which also keeps the private key
off the network on every renewal. `expose-fd listeners` is dropped: it hands
the listening sockets themselves to a client of that socket and only serves
seamless reloads, which this image never performs.

HAProxy binds a unix socket by creating `<path>.<pid>.tmp` and renaming it, so
it needs write access to the directory; the image now creates /var/lib/haproxy
owned by uid 1001 and docker carries that onto an empty named volume. Without
it HAProxy refuses to start.

Also in this commit:

- The visitor's address no longer leaves the process. `option forwardfor` is
  gone, X-Forwarded-For is deleted unconditionally, and X-Client-Id carries an
  HMAC of the address under the optional XFF_HMAC_KEY instead — one-to-one with
  the address, so a rate limit keyed on it is as precise, but not reversible.
  An empty key sends no header rather than one derived from an empty key.
- Logging, which was absent entirely. To stdout for `docker logs`, errors-only
  via the existing dontlog-normal. Both log-format and error-log-format are
  hand-written: the built-in formats open with %ci:%cp and would have logged
  the addresses the rest of this works to avoid. The pseudonym is computed by a
  tcp-request connection rule so a refused handshake has one too.
- TLS pinned: floor TLS 1.2, ECDHE-only in ECDSA and RSA variants, no session
  tickets, ALPN offering HTTP/2.
- HTTP redirects to HTTPS, excepting the ACME challenge path, plus HSTS at one
  day — short deliberately, since the header cannot be recalled once sent.
- timeout http-request, which `timeout client` cannot stand in for: that one
  resets on every byte, so a slow-drip client held a connection indefinitely.
- Backends re-resolve through the declared `resolvers docker`, which nothing
  referenced. Names were resolved once at boot, so a container recreated on a
  new IP was never noticed. init-addr libc,none lets HAProxy start anyway.
- The commented-out /ms deny rules are deleted. They would have blocked
  /ms/info and /ms/api/v2/whoami, both deliberately public.
- compose: build context is the repository root, as the Dockerfile's COPY
  expects and as CI already did; restart policy added, since an empty
  certificate volume is a fatal start-up error; the volumes section, which was
  missing, so the file can actually come up.

Verified on testnet2 against the real binary: config parses clean with the key
set, empty, and rejects a non-base64 key at parse time; a live stack confirms
the pseudonym is stable per address, differs between addresses, survives a
forged header, and that the client address appears nowhere in the log.
2026-08-07 13:38:40 +00:00
private-user f9dca2deff Block MS from the public entry
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 33s
2026-07-02 12:32:39 +03:00
private-user 7c8208fc61 Block MS from the public entry
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 40s
2026-07-02 12:20:25 +03:00
private-user e157a30c6d fix act_runner build job
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 43s
2026-03-06 13:02:41 +03:00
private-user c38062a851 add act_runner build job
Build docker image and push to registry.bitdeals.org / main-build-job (push) Failing after 31s
2026-02-09 11:42:36 +03:00
private-user 4d4ac3ce6f dockerfile fix 2025-10-13 12:45:52 +03:00
private-user b12569914b add registry 2025-03-19 13:38:33 +03:00
private-user 9491fcb362 add dockerfile and config 2024-11-02 17:20:01 +03:00
private-user d60140ae78 add dockerfile and config 2024-11-02 17:12:45 +03:00