67 lines
2.8 KiB
Markdown
67 lines
2.8 KiB
Markdown
# Bitcoin Pulse public ingress
|
|
|
|
Bitcoin Pulse uses the dedicated API hostname
|
|
`bitcoin-pulse.tobiasostner.de`. The native iOS client calls this hostname
|
|
without a path prefix. A same-origin path proxy is unnecessary because there is
|
|
no browser frontend, and no CORS headers are configured because native iOS
|
|
requests are not subject to browser CORS enforcement.
|
|
|
|
## DNS and TLS
|
|
|
|
The `bitcoin-pulse` A record under `tobiasostner.de` points to Tobserver's public
|
|
IPv4 address, `162.55.103.218`. There is no AAAA record until Tobserver has
|
|
working public IPv6 connectivity.
|
|
|
|
The NixOS nginx virtual host obtains and renews its certificate through the
|
|
existing ACME configuration and redirects plaintext HTTP to HTTPS. Only ports
|
|
80 and 443 are public ingress for the API. The application listens on
|
|
`127.0.0.1:3000`; port 3000 is not opened by the host firewall, so nginx is the
|
|
only public path to the backend.
|
|
|
|
## Proxy policy
|
|
|
|
nginx preserves the original request path and forwards it to
|
|
`http://127.0.0.1:3000`. It supplies `Host`, `X-Real-IP`, `X-Forwarded-For`, and
|
|
`X-Forwarded-Proto`, and uses short local-upstream timeouts: two seconds to
|
|
connect and ten seconds to read or send.
|
|
|
|
Requests are limited per source IP to an average of 300 requests per minute,
|
|
with a burst of 50 requests, and rejected with HTTP 429 when the burst is
|
|
exhausted. This allows normal polling and multiple devices behind a shared NAT
|
|
while bounding abusive traffic. Request bodies are limited to 16 KiB; the
|
|
current public API consists only of small GET requests.
|
|
|
|
## Deployment verification
|
|
|
|
After a human reviews and merges the change, deploy the resulting NixOS
|
|
generation and verify locally on Tobserver:
|
|
|
|
```console
|
|
systemctl is-active nginx.service bitcoin-pulse.service
|
|
ss -ltn '( sport = :3000 )'
|
|
curl --fail --show-error --silent http://127.0.0.1:3000/health \
|
|
| jq -e '.status == "OK"'
|
|
```
|
|
|
|
The socket listing must show only `127.0.0.1:3000`, not `0.0.0.0:3000` or the
|
|
public address. From a machine outside Tobserver, verify DNS, HTTPS, the health
|
|
endpoint, and each functional endpoint:
|
|
|
|
```console
|
|
dig +short A bitcoin-pulse.tobiasostner.de
|
|
curl --fail --show-error --silent \
|
|
https://bitcoin-pulse.tobiasostner.de/health \
|
|
| jq -e '.status == "OK"'
|
|
curl --fail --show-error --silent \
|
|
https://bitcoin-pulse.tobiasostner.de/block-height | jq -e .
|
|
curl --fail --show-error --silent \
|
|
https://bitcoin-pulse.tobiasostner.de/difficulty-adjustment | jq -e .
|
|
curl --fail --show-error --silent \
|
|
https://bitcoin-pulse.tobiasostner.de/price | jq -e .
|
|
```
|
|
|
|
The A lookup must return `162.55.103.218`. The HTTPS certificate must be valid
|
|
for `bitcoin-pulse.tobiasostner.de`; `/health` must return HTTP 200 and
|
|
`{"status":"OK"}`. The functional endpoints must return HTTP 200 and JSON after
|
|
the collectors have populated their data. A connection from outside Tobserver
|
|
to TCP port 3000 must fail.
|