Production deployment

This page turns the basic examples into a repeatable long-running service setup.

The canonical runtime contracts remain in the main repository. This page is an operator-oriented recipe.

1. Install a release

GitHub Releases publishes two x86-64 archive families:

tcpcc-6.18.N-linux-x86_64-glibc.tar.xz
tcpcc-6.18.N-linux-x86_64-musl.tar.xz

Use the glibc archive for typical Debian/Ubuntu-style systems and the musl archive for Alpine.

The archive is relocatable and contains:

bin/tcpcc
libexec/tcpcc/vmlinux
share/doc/tcpcc/...

Installing beneath /usr/local:

sudo tar -xJf tcpcc-6.18.N-linux-x86_64-glibc.tar.xz -C /usr/local
/usr/local/bin/tcpcc --help

Open GitHub Releases

Note

The default nft-lib backend dynamically loads the target system's libnftables. Install the normal nftables/libnftables runtime, or explicitly select one of the supported executable/iptables compatibility backends.

2. Create the service configuration

Create /etc/tcpcc/tcpcc.toml:

version = 1
cc = "bbr"
memory_mib = 128
firewall_backend = "nft-lib"

[[forward]]
listen = "203.0.113.10:443"
backend = "127.0.0.1:8443"

The backend application should already be listening on the configured loopback port.

For multiple public ports:

[[forward]]
listen = "203.0.113.10:443"
backend = "127.0.0.1:8443"

[[forward]]
listen = "203.0.113.10:8443"
backend = "127.0.0.1:9443"

All public listeners in one process currently use one address family and distinct public ports.

3. Enable forwarding

tcpcc diagnoses forwarding state but deliberately does not rewrite the host's global policy.

For IPv4:

sudo sysctl -w net.ipv4.ip_forward=1

For IPv6:

sudo sysctl -w net.ipv6.conf.all.forwarding=1

Make the setting persistent using the mechanism appropriate for your distribution.

4. Run the read-only preflight

Before mutating TUN/firewall state:

sudo /usr/local/bin/tcpcc   --check   --config /etc/tcpcc/tcpcc.toml

The check validates, among other things:

  • configuration schema/endpoints;
  • effective CAP_NET_ADMIN;
  • readable/writable /dev/net/tun;
  • forwarding for the selected family;
  • the selected firewall backend;
  • the hosted image shape/path;
  • existing tcpcc firewall ownership state.

It intentionally does not require the outer host to advertise BBR.

5. Start it manually once

sudo /usr/local/bin/tcpcc   --config /etc/tcpcc/tcpcc.toml

Verify the public address/port from another machine before placing the service under a process manager.

6. Example systemd unit

tcpcc does not currently ship a distribution-specific unit. The following is an operator example:

[Unit]
Description=linux-tcp-cc
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStartPre=/usr/local/bin/tcpcc --check --config /etc/tcpcc/tcpcc.toml
ExecStart=/usr/local/bin/tcpcc --config /etc/tcpcc/tcpcc.toml
Restart=on-failure
RestartSec=5
KillSignal=SIGTERM
TimeoutStopSec=15

[Install]
WantedBy=multi-user.target

Save it as /etc/systemd/system/tcpcc.service, then:

sudo systemctl daemon-reload
sudo systemctl enable --now tcpcc
sudo systemctl status tcpcc

tcpcc consumes SIGTERM through its normal event loop, stops admission, drains active flows for the configured grace period, stops hosted Linux, removes owned firewall state, and closes the nonpersistent TUN.

Warning

A process cannot run cleanup after receiving SIGKILL. tcpcc marks its firewall resources so a later startup can detect stale ownership rather than deleting unknown state. Do not use KillMode/timeouts that unnecessarily force SIGKILL during normal shutdown.

7. Check the backend and public path separately

Remember that there are two different TCP connections:

Internet client
   ↕ hosted Linux TCP (BBR/CUBIC)
tcpcc
   ↕ ordinary host-loopback TCP
127.0.0.1 backend

Testing only 127.0.0.1:8443 proves the application works. It does not prove the public TUN/DNAT/hosted-TCP path works.

Always test the public address from an external peer.

8. Updating

Release tags follow the pinned Linux stable patch version. Download the next immutable archive, stop tcpcc cleanly, replace the installed archive contents, and start again.

Do not overwrite or reinterpret old release tags; the project intentionally treats release artifacts as immutable.

For the canonical release policy, see docs/releases.md.