# `socket_proxy` Exposes a service running on a private Tailscale host through a public TCP port on an edge machine, using `systemd-socket-proxyd`. Writes a `.socket` and a `.service` unit, enables the socket, opens the UFW port, and checks the upstream is reachable. ## Usage ```yaml - ansible.builtin.include_role: name: socket_proxy vars: socket_proxy_name: fulcrum-ssl # -> fulcrum-ssl-proxy.{socket,service} socket_proxy_description: "Fulcrum SSL" # -> "Fulcrum SSL Proxy Socket" socket_proxy_listen_port: "{{ fulcrum_ssl_port }}" socket_proxy_upstream_host: "{{ fulcrum_tailscale_hostname }}" ``` `socket_proxy_upstream_port` defaults to `socket_proxy_listen_port`, which is what all three current callers want. ## Optional unit settings These exist because the **live** `bitcoin-p2p-proxy` units on vipy carried settings the playbook never wrote. Somebody added them by hand, so running `deploy_bitcoin_knots_playbook.yml` would have silently removed them: | Variable | Emits | Why it matters | |---|---|---| | `socket_proxy_free_bind` | `FreeBind=true` in `[Socket]` | Lets the socket bind to an address that is not up yet. Without it the socket can fail to start on boot. | | `socket_proxy_documentation` | `Documentation=` in both units | Cosmetic. | | `socket_proxy_timeout_stop_sec` | `TimeoutStopSec=` | Bounds how long a stop can hang. | | `socket_proxy_log_to_journal` | `StandardOutput=journal` + `StandardError=journal` | Cosmetic on modern systemd, which defaults to the journal anyway. | Only `bitcoin-p2p` passes any of them. ## `socket_proxy_ufw_comment` Defaults to `" public access"`, which reproduces the live rule comment for bitcoin-p2p and fulcrum-ssl. **datum-stratum must pass it explicitly** — its live comment is `DATUM Gateway Stratum public access` while the derived default would be `DATUM Stratum public access`, and UFW treats the comment as part of the rule, so the mismatch rewrites the rule on every run. ## The upstream check never fails the play `wait_for` on the upstream carries `failed_when: false`. The proxy is correctly configured whether or not the backend happens to be up, and this is the one task that depends on another machine. The original plays used `ignore_errors: yes`, which prints a red "ignoring" line; `failed_when: false` is the quieter equivalent. ## Restarts The handler restarts the `.socket`, not the `.service` — that is what picks up a changed unit; the service is started by the socket on the next connection. **Restarting a socket drops connections that are currently open through it.** For bitcoin-p2p that means peers reconnect; for datum-stratum it means a mining client has to reconnect and may lose in-flight shares. The handler only fires when a unit file actually changes.