tnl.dev :: docs

aws publishers.

Run publishers in your AWS network using your own infrastructure tools.

run publishers in your aws account

Run a publisher on an EC2 instance or in a container that can reach your database or API. You manage the AWS resources; tnl connects visitors to the services you've configured. The publisher needs outbound connections, not a public inbound port.

declare and apply services

For example, let your team connect to orders.internal:5432 through a publisher in the production group:

tnl.config.ts
import { defineConfig } from "@tnldotdev/tnl/config";
 
export default defineConfig({
  team: "shop",
  publisherGroups: { production: { description: "production network" } },
  services: {
    orders: {
      publisherGroup: "production",
      protocol: "postgres",
      target: { type: "address", address: "orders.internal:5432" },
      access: { team: true },
    },
  },
});
tnl auth login --team shop
tnl check
tnl apply
tnl publisher provision --group production --instance replica-1 --output-file /private/tnl/replica-1.json

Use an existing private directory outside the repository. Each independently running replica needs its own instance name, signing identity, and durable identity directory. Provisioning writes a private credential file without overwriting one. It does not create AWS resources or store secrets in AWS.

start the publisher

Install a matching tnl release, make the credential available to the process, and run it under your supervisor:

tnl --no-config publisher serve --identity-file /run/tnl/replica-1.json --identity-dir /identity --state-dir /state

The credential already identifies the server, team, project, group, and replica. Use it without extra selection flags. In a container, pin the image by digest and invoke /usr/local/bin/tnl with the same arguments.

  • Preserve /identity across restarts and replacements. It holds signing and TLS keys, certificates, pending issuance, and the writer lock. An exported signing credential alone cannot restore already-issued TLS private keys.
  • Keep /state on local disk. SQLite and its WAL must not live on EFS or NFS.
  • Never run two processes against the same replica identity directory. Stop the old process before starting its replacement. Other independently provisioned replicas can keep accepting new visitors; existing streams are not replayed.
  • Allow outbound DNS, control HTTPS, relay TCP/UDP, and the selected target ports. Publishers need no inbound public listener.

For ECS, inject the replica's credential as TNL_GROUP_IDENTITY on every launch, or mount it as a private file. Pin the Secrets Manager version and limit access to that replica. Use a separate ECS service per identity with at most one active task; a rolling deployment must not overlap old and new tasks for that identity. Use replica-private persistent storage for /identity, and test its locking, atomic replacement, and sync behavior before relying on it.

AWS target discovery uses the publisher's ordinary AWS credential chain. Grant only the metadata access needed by the declared targets. A static address target does not need AWS metadata permissions. See target configuration.

verify and replace

tnl status --scope=server
tnl publisher list --team shop
tnl connect orders

Use the printed settings with psql and run a query. This checks the path all the way to the database; an AWS task marked RUNNING only tells you the process started.

To replace a process, retain its complete identity directory and use the same credential. To replace an identity, stop the process, revoke the old publisher, provision a new instance, and update the deployed secret. Stopping AWS resources does not revoke publisher access. See publisher groups for identity ownership, revocation, and group selection.