Skip to content
Fixedmark
Connectors

Inbound

Updated

Connectors: fixedmarkd on your machine

A connector is fixedmarkd, the program that serves your tunnel routes from a machine with no public IP. It dials out on port 443 to each Fixedmark IP that carries one of its routes and holds a session open, and the node sends each partner connection down that session to a local target such as 127.0.0.1:8080. For an http route it also orders the hostname's certificate and terminates TLS on your machine. Your machine opens no inbound port.

Docs preview: Fixedmark is not live yet. Endpoints are issued at launch, and these pages describe planned launch behavior. Anything marked planned may change. Join early access to get yours first.

What a connector is

A connector is the origin of every tunnel route, and one of two kinds of origin on a dedicated inbound IP. A route's origin is either a host the node dials, which only a dedicated IP can do, or a connector and a target on the connector's machine. Use a connector when the service sits behind home NAT, office NAT, or carrier-grade NAT, or when you do not want to open a port to the internet.

  • fixedmarkd dials each Fixedmark IP that carries one of its routes on TCP 443 with TLS 1.3, the server name connector.fixedmark.net, and the ALPN fm-connector/1. It needs outbound 443 only.
  • It holds one session per IP, so two for a tunnel route on its two shared IPs, and opens a stream inside a session for each partner connection.
  • The node checks the partner list before a stream opens, then meters the bytes as inbound and writes the connection log row, exactly as for a host origin.
  • For a tls or tcp route the bytes pass through unchanged. For an http route fixedmarkd terminates TLS on your machine with a certificate it orders itself, as Tunnels explains. No node ever terminates the partner's TLS.

Before you start

  • A plan with tunnels. Tunnels on Pro and up, with a dedicated inbound IP as an add-on at $9 per IP-month. Your plan also sets how many connectors your org can hold, as Limits lists.
  • An app for the connector and its routes. fm apps list prints its id and name.
  • A Linux or macOS machine on amd64 or arm64 that can reach the service and make outbound connections to port 443. fixedmarkd does not run on Windows yet.
  • The partner's source addresses, as IPv4 addresses or CIDRs.

Create a connector

Name the connector after the machine or the service it serves. A name is 1 to 64 letters, digits, dots, dashes, or underscores, starts with a letter or digit, and is unique within the app.

Terminal
fm connectors create --app APP_ID --name billing-db

fm writes the connector's token to a file in the current directory, readable by you only, and prints the install line. The token is shown this once. Fixedmark stores only its SHA-256 hash and cannot show it again.

connector billing-db created id=CONNECTOR_ID
token_prefix xxxxxxxx
token written to fm-connector-billing-db.token (mode 0600)
install sudo fixedmarkd install --token-file fm-connector-billing-db.token
Run the install line from this directory. The token is never shown again.

A token is fmc_ followed by 52 characters. fm connectors list and the dashboard show only the first 8 characters after fmc_, as its prefix. To write the file somewhere else, add --token-file PATH. fm never replaces a file that exists. The dashboard's connectors page for the app creates a connector too, and shows the same install line once.

Keep the token in the file. Do not paste it into a command, since a command line lands in shell history and the process list. Anyone with the token can attach a connector to your routes, so rotate it if it leaks.

Install fixedmarkd and the service

fixedmarkd is the connector program. It is separate from fm, needs no fm on the machine, and reads no fm configuration. The fixedmarkd download is not published yet.

On the machine that holds the service, from the directory with the token file, run the install line:

Terminal
sudo fixedmarkd install --token-file fm-connector-billing-db.token
  1. sudo fixedmarkd install copies the token to a root-only file, writes the service, and starts it.
  2. The service starts fixedmarkd run, which attaches within seconds once a route names the connector.
  3. systemd also gives the service a state directory for its certificate keys. On macOS install creates one at mode 0700, owned by nobody.

After the install, delete the token file in your directory. The service holds its own copy.

Point a route at the connector

A route takes one origin. Pass --connector and --to for a target on the connector's machine. The target is host:port as that machine sees it, so 127.0.0.1, a private address, or a local name all work. Leave out --dedicated-ip and the route is a tunnel on the shared pool.

fm routes create --app APP_ID --kind http --name billing \
  --connector billing-db --to 127.0.0.1:8080 \
  --partner 198.51.100.0/24

Partners then reach https://billing.<org-slug>.<zone>, and each request reaches 127.0.0.1:8080 on your machine. tls and tcp routes take a connector the same way, with --kind tls or --kind tcp. fixedmarkd reads new routes from its plan within 60 seconds, so it needs no restart.

Connector route refusals
CodeMeaning
route.origin_conflictThe request names both a host origin and a connector.
route.connector_not_foundNo connector with that name or id exists in the route's app.
route.connector_disabledThe connector is disabled. Contact support.
route.target_invalidThe target is not host:port with a port from 1 to 65535.
route.proxy_protocol_host_only--proxy-protocol was set on a host origin.

Run it in the foreground

To try a connector before you install the service, run it in a terminal. It reads the token from the file, which must be readable by you only.

Terminal
chmod 600 fm-connector-billing-db.token
fixedmarkd run --token-file fm-connector-billing-db.token --log-format text

Without --token-file, fixedmarkd run reads the token from FIXEDMARKD_TOKEN, else from ~/.config/fixedmarkd/token, or ~/Library/Application Support/fixedmarkd/token on macOS. Stop it with Ctrl+C. It waits up to 10 seconds for open partner connections to finish, then exits 0.

fixedmarkd run flags
FlagDefaultMeaning
--token-fileFIXEDMARKD_TOKENThe token file. Refused when group or others can read it.
--log-formatjsonjson or text. --log is the same flag.
--api-urlhttps://api.fixedmark.comThe control plane. FIXEDMARKD_API_URL sets it too.
--connect-timeout5sHow long to wait for the local target to accept.
--max-streams256Partner connections open at once, from 1 to 2048. Past it a new one is refused with busy.
--state-dir$STATE_DIRECTORY, else $XDG_STATE_HOME/fixedmarkd, else ~/.local/state/fixedmarkdWhere the ACME account and each http route's key and certificate live, at mode 0700. See Certificates.
--status-file$XDG_RUNTIME_DIR/fixedmarkd/status.jsonWhere fixedmarkd status reads the state. Without XDG_RUNTIME_DIR, and for the service, /run/fixedmarkd/status.json.

Run it as a service

sudo fixedmarkd install sets up the service for your OS. Run it again with a new --token-file after a rotate. Add --dry-run to print the files and commands without writing anything.

What fixedmarkd install writes
OSServiceTokenLogs
Linuxfixedmarkd.service, a systemd unit with its own dynamic user/etc/fixedmarkd/token, mode 0600journalctl -u fixedmarkd
macOSnet.fixedmark.fixedmarkd, a launchd daemon that runs as nobody/Library/Application Support/fixedmarkd/token, mode 0600/Library/Logs/fixedmarkd/fixedmarkd.log
systemctl is-active fixedmarkd
journalctl -u fixedmarkd -f
  • systemd restarts the service 5 seconds after any exit except exit codes 2, 3, and 4, which a restart cannot fix.
  • launchd restarts every exit, so on macOS the service waits 5 minutes before it exits 3 or 4. A revoked token then asks the control plane once every 5 minutes.
  • sudo fixedmarkd uninstall stops the service and removes the files fixedmarkd install wrote. It leaves any file it did not write, and it keeps the state directory, so the ACME account and the certificate keys stay on the machine until you remove the directory. On another OS, install exits 2 with fixedmarkd.install_unsupported.

Check the status

Terminal
fixedmarkd status
sudo fixedmarkd status --token-file /etc/fixedmarkd/token

fixedmarkd status prints one line per IP with its state, connecting, attached, detached, or stopped, the node, and the open streams. A CERTS table follows with one row per http route's hostname and its certificate's state. With --token-file it adds the control plane's view of each session. --json prints the status file, with the routes, the certificates, and each http route's counters.

No endpoints yet
Until a route names the connector, fixedmarkd status prints no endpoints yet and the log says plan has no routes yet. Create a route with --connector and the session attaches within a minute.

Fixedmark shows each placement's health beside the route. A placement reads healthy while a session to its IP is attached. When no session on that IP has been seen for 20 seconds, it reads no_session, the route's roll-up turns degraded or down, and the webhook route.health fires with origin_kind and connector_id. While no session is attached, a partner's connection opens and then closes, and your connection log shows result connector_offline.

The plan

fixedmarkd learns its routes from a plan it reads from the control plane every 60 seconds. After a dial fails it reads the plan again within about 8 seconds, then backs off to once a minute. The plan is version 2. It names each route's id, name, kind, hostname, target, and placements, the IPs to dial, and for http routes the CA and the challenge relay to use.

  • A field fixedmarkd does not know is ignored, so a control plane that adds an optional field never stops the fleet.
  • A newer version than fixedmarkd reads stops it with exit code 4, fixedmarkd.plan_version. Upgrade fixedmarkd.
  • An older version stops it with exit code 5, fixedmarkd.plan_version_old, and the service restarts until the control plane is upgraded.
  • A plan with a bad entry is refused whole, logged, and read again. The last good plan keeps serving.

Certificates

For each http route, fixedmarkd orders a certificate for the hostname by ACME DNS-01 and keeps the key in its state directory. Fixedmark only publishes the challenge record. No key leaves the machine. Tunnels covers the order, the renewal, and the weekly budget.

  • Without a state directory fixedmarkd issues no certificate, and an http route refuses partners with cert_unavailable.
  • Run one fixedmarkd per state directory. Two on one directory would order the same certificates twice.
  • Keep the state directory when you move the service. With an empty one, fixedmarkd makes a new key and orders each certificate again. Within 90 days of a hostname's last certificate, Fixedmark counts that order as a renewal, so it does not use the weekly budget. Let's Encrypt still allows only 5 certificates for the same names a week, so repeated moves can hit that limit. The route then refuses partners with cert_unavailable until the limit clears.

Exit codes

fixedmarkd exit codes
CodeMeaning
0Stopped by SIGINT or SIGTERM, after up to 10 seconds for open streams to finish.
1An unexpected error, such as fixedmarkd.api_not_found when the API URL serves no plan, or fixedmarkd.install_foreign_file when a service file exists that fixedmarkd did not write. Also fixedmarkd.state_dir when the state directory cannot be read or written.
2Bad usage. Also fixedmarkd.token_file_mode (the token file is readable by group or others), fixedmarkd.token_missing, fixedmarkd.token_malformed, fixedmarkd.api_url_insecure, fixedmarkd.install_unsupported, fixedmarkd.install_needs_root, and fixedmarkd.state_dir (the state directory is a symbolic link or another user's).
3The control plane refused the token with connector.token_invalid, so install a new token. Or Fixedmark disabled the connector with connector.disabled, which a new token does not change, so contact support.
4The control plane sent a plan version this fixedmarkd does not read, fixedmarkd.plan_version. Upgrade fixedmarkd. The Linux service does not restart on it, and the macOS service waits 5 minutes first.
5The control plane sent an older plan version than this fixedmarkd reads, fixedmarkd.plan_version_old. The control plane is behind, and the service restarts until it catches up.

fixedmarkd run --help prints the same table.

Log lines

fixedmarkd writes one JSON line per event to standard output, or text with --log-format text. Every line carries service (fixedmarkd), version, and direction, every line after the first plan read adds connector_id, and no line carries the token.

fixedmarkd log lines
LineWhen
connector startingAt start.
plan refreshedEach plan read, every 60 seconds, with routes and endpoints.
plan has no routes yetThe connector exists, but no route names it.
connector attachedA session is up, with ip, node_id, and routes.
connector detachedThe session ended, with the reason and retry_in_ms.
connector dial failedThe machine could not reach the IP on 443.
stream opened, stream closedOne partner connection, with partner, target, bytes, and result.
stream cap reachedEvery stream slot is in use. New partners are refused with busy.
connector token rejectedThe control plane refused the token. Exit 3 follows.
connector draining, connector stoppedShutdown.

PROXY protocol v2

Your service sees each partner connection arrive from fixedmarkd on its own machine. To give a tcp or tls target the partner's address, create the route with --proxy-protocol, or proxy_protocol: true in the API origin. fixedmarkd then sends a PROXY protocol v2 header before the first byte. The source is the partner's address and port, and the destination is the Fixedmark IP and the route's port. An http route takes no PROXY header: fixedmarkd sets X-Forwarded-For instead.

Terminal
fm routes create --app APP_ID --kind tcp --name db \
  --connector billing-db --to 127.0.0.1:5432 --proxy-protocol \
  --partner 198.51.100.0/24
Turn it on only when the service expects the header, as HAProxy, NGINX with proxy_protocol, and PostgreSQL poolers such as PgBouncer can. A service that does not expect it reads the header as data and fails the connection.

Limits

Connectors by plan
PlanConnectors per org
Pro5
Business20
Scale50

These counts are proposed and may change before connectors leave early access. connector.quota answers a create past your plan's count, and connector.not_entitled (402) answers one on a plan without tunnels.

  • fixedmarkd holds up to 256 partner connections open at once by default. Past that it refuses new ones with the reason busy, and the partner's connection closes. --max-streams changes the count.
  • The node gives one session 1000 streams. Past that a partner gets connector_busy.
  • One session per connector and IP. A second fixedmarkd with the same token replaces the first, so run one per token. For more capacity, create more connectors.
  • fixedmarkd pings the node every 15 seconds. The node closes a session that sends nothing for 45 seconds, and fixedmarkd reconnects.

What a connector cannot do:

  • Carry UDP. Routes are TCP, and tls and http routes are TLS over TCP.
  • Open a port outside the route ranges. Partners reach ports 20000 to 29999 for tcp routes, and 443 for every other kind, as inbound limits lists.
  • Bypass the partner list. The node admits only the partner addresses on the route, before anything reaches your machine.
  • Reach a target that no route names. fixedmarkd opens only the targets in its plan and refuses any other with target_not_in_plan.

Troubleshooting by close reason

Find the reason in the connector detached line, or the result in the connection log row, then follow its row.

Session close reasons
ReasonMeaningWhat to do
connector_replacedA second session with the same token attached to the IP. The newest one wins.Stop the other fixedmarkd, or create a second connector for it.
token_rotatedThe token was rotated. The old token now exits 3.Run sudo fixedmarkd install --token-file with the new token file.
connector_disabledFixedmark staff disabled the connector.Contact support.
connector_unboundNo route on the IP names the connector anymore, for example after a route moved to another group.Nothing when the route moved: fixedmarkd reads its plan and dials the new IPs. Otherwise create a route with --connector, or uninstall the service.
staff_disconnectFixedmark staff reset the session.Nothing. fixedmarkd reconnects on its own.
keepalive_timeoutThe node heard nothing for 45 seconds.Check the machine's network. If it repeats every few minutes, a NAT or firewall on its path drops idle flows.
shutdownThe node restarted for an update.Nothing. fixedmarkd reconnects within seconds.
Partner connection results on a connector route
ResultMeaningWhat to do
connector_offlineNo session was attached on the IP.Check fixedmarkd status and the service's logs for connector dial failed.
target_unreachablefixedmarkd could not open the target, with a reason such as connect_refused, timeout, dns, or busy.Check the service listens on the route's --to address from the connector's machine.
connector_busyThe session's 1000 streams were in use.Set idle timeouts on the partner side, or spread partners over more connectors.

When you write to support, include the connector_id and the reason from your log. Never include the token.

Rotate or delete a connector

Terminal
fm connectors rotate --app APP_ID billing-db
sudo fixedmarkd install --token-file fm-connector-billing-db.token
fm connectors delete --app APP_ID billing-db

A rotate writes a new token file and closes the session at once, so install the new token right away. A delete is refused with connector.in_use while a route names the connector. Delete or repoint those routes first.

Frequently asked questions

Does a connector need an open inbound port on my machine?

No. fixedmarkd dials out to your Fixedmark IP on port 443 and holds the session open. Partner connections come back down that session, so the machine needs outbound 443 only.

Do partner allowlists still work with a connector?

Yes. Partners connect to the route's hostname or IP as with any inbound route, and the node admits only the partner addresses you list before anything reaches your machine.

Can I run fixedmarkd on Windows?

Not yet. fixedmarkd runs on Linux and macOS.

Make it fixed.

Fixedmark is in early access. Join the list to get dedicated static IPs when your region opens.