Kylin010/tcpfit: TCP tuning derived from measurements on each machine, not copied presets
按每台机器实测推导的 TCP 调优工具 —— 不套用固定参数,实测 BDP 与限速器拐点
At a glance
- What is it?
- tcpfit is a Shell script that profiles a Linux host, measures its bandwidth-delay product and policer knee, and writes 32 sysctl parameters plus an HTB shaper. It is for people running proxies and VPS instances who distrust one-size-fits-all tuning guides.
- Who is it for?
- Adopt tcpfit if you run a Linux proxy or VPS on systemd with iproute2, you have a nearby iperf3 peer, and you want tuning values derived from your own link rather than copied from a guide. Skip it if the bottleneck is an international path rather than the port, if you are on OpenVZ or LXC where tc and initcwnd may be restricted, or if you cannot supply an iperf3 endpoint for sweep.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 19 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem tcpfit targets: tuning guides that assume someone else's link
Most TCP tuning advice on the internet is a fixed list. You paste a dozen sysctl lines into /etc/sysctl.conf, reboot, and hope. Those values were derived on somebody else's machine, on somebody else's route, at some other time of day. tcpfit takes the opposite position: the buffer sizes and the shaper rate should come from what the machine in front of you actually does.
The README states the project's premise directly: it derives values from per-machine measurement rather than applying fixed parameters, measuring BDP and the policer knee. That word choice matters. A policer knee is the throughput level at which an upstream rate limiter starts dropping packets, and it is not something you can read off a spec sheet. If your VPS provider shapes you at 500 Mbit while the NIC negotiates 10 Gbit, a tuning guide written against the NIC speed will produce buffers that are wrong in both directions.
The intended audience is narrow and specific. The repository topics list bbr, linux, network-tuning, performance, proxy, shell, tcp and vps. The subcommand examples use --role proxy, and the tuning archives are described in terms of moving between datacenters (the example name is a Chinese phrase meaning roughly "before switching datacenters"). This is a tool for people running forward proxies, relays and small VPS instances who care about a single link's throughput and are willing to spend ten minutes measuring it.
What tcpfit actually changes on disk and in the kernel
The README lists 32 sysctl parameters across six categories. Congestion control moves to tcp_congestion_control=bbr with default_qdisc=fq. Buffer sizes cover tcp_rmem, tcp_wmem, rmem_max, wmem_max and tcp_mem. Window behaviour covers tcp_window_scaling, tcp_moderate_rcvbuf and tcp_adv_win_scale. Queue and backlog parameters include netdev_max_backlog, netdev_budget and somaxconn. Connection handling touches tcp_tw_reuse, tcp_fin_timeout and ip_local_port_range. Startup behaviour sets tcp_slow_start_after_idle=0 and initcwnd 32. Egress shaping is an HTB global ceiling with an fq leaf for pacing.
That is a wide blast radius, and the project is unusually explicit about where it lands. Changes go only into these paths, and the README states /etc/sysctl.conf is not touched:
/etc/sysctl.d/99-tcpfit.conf
/etc/systemd/system/tcpfit-qdisc.service
/usr/local/sbin/tcpfit-qdisc.sh
/etc/networkd-dispatcher/routable.d/50-tcpfit-initcwnd
/etc/modules-load.d/tcpfit-bbr.conf
/var/lib/tcpfit/Keeping the sysctl drop-in separate from the distro's main file is the right call. It means a package upgrade to procps or systemd will not silently merge your tuning into a file a future administrator edits by hand. It also means removal is a file deletion rather than a diff.
The one thing that escapes that list is swap. If you run harden --swap, tcpfit creates /swapfile and adds a line to /etc/fstab. Neither is removed by a plain rollback. You need rollback --purge-swap. The README gives the reason plainly: deleting swap that is in use can OOM the machine immediately. That is a defensible default, but it does mean an incomplete rollback is the normal case, not the exception, for anyone who used harden.
Installing tcpfit and running a first auto-tune
The README gives a single install line. It downloads the script and runs it, then drops a copy at /usr/local/bin/tcpfit so later invocations are just the command name.
bash <(curl -fsSL https://raw.githubusercontent.com/Kylin010/tcpfit/main/tcpfit.sh)After that you get a menu. Option 1 is the auto-tune path, described in the menu as taking about ten minutes. The README says it asks three questions: bandwidth, a speed-test peer, and the machine's role. Once you confirm, it runs to completion without further prompts.
The bandwidth prompt is the interesting part, because it accepts four kinds of input. A number means derive buffers from that figure and then measure the knee. Pressing enter means measure the bandwidth live first, then measure the knee. Entering m means supply a rate limit directly and skip the knee sweep. Entering 0 means no shaping at all.
If you would rather not sit in a menu, everything is also a subcommand. A basic tune with an explicit role and bandwidth looks like this:
tcpfit tune --role proxy --bw 500
tcpfit tune --role proxy --bw 500 --save 换机房前The second form names the resulting archive, which is what you would do before a planned migration. There is also a detect subcommand for a machine profile, and a status subcommand for the current configuration. Note the README's statement that the script does not auto-update: what you install stays installed. Upgrading is an explicit act through menu option 8 or tcpfit update, which only checks and then asks.
The knee sweep, and why it looks upward instead of downward
The sweep is the part of tcpfit that has no equivalent in a static tuning guide, so it is worth understanding its logic before you trust it. The README describes the first step as an unshaped run to see whether anything is policing you. Three outcomes are documented.
Low packet loss means there is no policer and tcpfit applies no shaping. High packet loss means a policer exists, and the tool sweeps upward from the measured throughput to find the knee. Throughput above 2500 Mbit exceeds the scan ceiling and the sweep is skipped, though the README notes --cap can adjust that.
The direction of the search is counterintuitive until you read the explanation: the knee sits above the unshaped throughput, because driving past the policer makes throughput fall off, so you search upward. That is a real design decision and it is documented rather than hidden.
The failure mode is documented too. If the sweep covers the whole interval without finding a knee, tcpfit takes the upper bound of the interval as the knee. That is a guess dressed as a measurement, and the README says so, recommending the m input to specify the rate manually in that case. Anyone automating tcpfit should treat that outcome as a signal to stop, not as a result.
The sweep needs a nearby iperf3 peer. The README states that if iperf3 is missing, tcpfit will install it through the package manager after asking you. That is a network dependency at tune time, not just at install time, and it is the main reason this tool cannot run unattended on an isolated host.
PPPoE and the ip-up hook in 0.5.8
Release 0.5.8 added support for dial-up style links, and the mechanism is worth noting because it shows where the project's complexity budget went. The README describes the signature of such a machine as a default route that looks like default dev ppp0 scope link, a point-to-point route with no via.
The problem is that every redial produces a new interface. The qdisc and the routing window settings disappear with the old one. tcpfit's answer is a hook at /etc/ppp/ip-up.d/50-tcpfit that re-applies shaping and initcwnd after the link comes up. The README states the hook only affects the interface that was tuned, not other ppp links on the machine, and that machines without /etc/ppp/ip-up.d are unaffected and get nothing created.
That scoping matters. A hook that blindly re-applied settings to every ppp interface would be a liability on a router with multiple uplinks. The stated behaviour is the conservative one. What the README does not describe is what happens if the interface name changes between redials rather than just the interface state, which is the case that would actually break the hook. Treat that as undocumented rather than solved.
Rollback, snapshots and the 0000 factory archive
Before the first change, tcpfit writes a snapshot to /var/lib/tcpfit/pre-tune.snapshot containing the original values of all 32 parameters. Since 0.5.7, that snapshot is also kept as archive 0000, labelled as the factory state, and it cannot be renamed or deleted on its own. Running archive restore 0000 goes through the same rollback path as the rollback subcommand.
The README is precise about what rollback means: it writes the recorded values back item by item, it does not restore defaults. That distinction is the whole point. A machine that was already tuned by hand before tcpfit ran will return to that hand-tuned state, not to a stock kernel.
Ordinary archives live in /var/lib/tcpfit/archives/. Basic tuning saves one automatically; auto-tune saves after final shaping and verification. Indexes can be given as 10 or 0010, and names containing spaces need quoting.
Restoring a normal archive also restores the sysctl boot configuration and the shaping service. The README notes that when routing window settings are involved, the restore relies on the networkd-dispatcher hook, and that a missing directory produces a message saying routing can only be restored immediately, with the operation returning failure. It also warns that a failed restore may have already applied part of the settings, so you should inspect before retrying. That is an honest description of a partial-failure state, and it is the kind of thing most tools omit.
Uninstall defaults to deleting archives. --keep-archives preserves them. If rollback fails, uninstall stops and keeps the archives. Uninstall does not remove swap, iperf3 or ping.
Where tcpfit is the wrong tool
The README's known limitations section is short and specific, and two entries deserve emphasis.
The first is the international link case. When the bottleneck is an international path rather than the port, shaping brings no improvement, but the output looks entirely normal. That is the worst kind of failure: silent. You get a completed run, a saved archive, and a shaper applied for no benefit. If your users' complaints are about cross-border latency rather than throughput on a single hop, tcpfit is measuring the wrong thing.
The second is the platform constraint. tcpfit needs Linux, systemd and iproute2. On OpenVZ or LXC, tc and initcwnd may be restricted. Container guests frequently have no control over qdiscs at all, so the shaping half of the tool may fail or silently no-op while the sysctl half succeeds. Check that before assuming a successful run means a shaped link.
A third constraint is implied rather than stated: sweep needs a nearby iperf3 peer. If you cannot provide one, you lose the measurement that distinguishes this tool from a preset list, and you are left with the numeric-bandwidth path, which is the thing the project exists to avoid.
The multi-machine orchestrator is in the repository under orchestrator/ and inventory/, with a documented command set including --only, --tag, -j, --dry-run and a run passthrough. The README labels it not yet validated in real environments and advises against using it. That is a clear boundary, and it should be respected rather than tested in production.
How tcpfit differs from reading a sysctl tuning guide
The obvious alternative is a tuning guide: a page of sysctl values you paste into /etc/sysctl.conf and apply with sysctl -p. The difference in approach is total. A guide gives you one set of numbers for every machine. tcpfit gives you numbers derived from a measurement on the machine you ran it on, and it records the previous values so the change is reversible.
That reversibility is the second real difference. A pasted guide leaves no record of what was there before. tcpfit writes a snapshot before its first change and keeps a factory archive that cannot be deleted. If you have ever inherited a server where someone applied tuning years ago and nobody remembers the original values, that archive is the feature you want.
The third difference is the shaper. Guides generally stop at kernel parameters. tcpfit also applies an HTB ceiling with fq pacing, derived from the knee it measured. That is more invasive and more likely to be wrong on a shared host, but it is also the only part that can address an upstream policer.
The cost of all this is time and dependencies. A guide takes thirty seconds and works offline. tcpfit's auto path takes about ten minutes, needs a peer, and may install iperf3. If you are tuning a throwaway container for a one-off test, the guide is the better choice. If you are tuning a production relay you will keep for a year, the measurement and the rollback path are worth the ten minutes.
Editorial conclusion
Adopt tcpfit if you run a Linux proxy or VPS on systemd with iproute2, you have a nearby iperf3 peer, and you want tuning values derived from your own link rather than copied from a guide. Skip it if the bottleneck is an international path rather than the port, if you are on OpenVZ or LXC where tc and initcwnd may be restricted, or if you cannot supply an iperf3 endpoint for sweep. Before trusting it, read the snapshot at /var/lib/tcpfit/pre-tune.snapshot, confirm the 32 recorded values match what you expect, and run tcpfit rollback once on a staging box to see the restore path work end to end. The multi-machine orchestrator under orchestrator/fleet.py is explicitly not validated in real environments, so treat it as unusable for production.
Frequently asked questions
What does TCP stand for in Kylin010/tcpfit?
The README does not expand the acronym. The repository topics and the parameters it writes place it in the Transmission Control Protocol context: it sets tcp_congestion_control, tcp_rmem, tcp_wmem and related keys.
How do I install Kylin010/tcpfit?
The README gives one command that downloads and runs the script, after which it is installed to /usr/local/bin/tcpfit and can be invoked as tcpfit.
Does Kylin010/tcpfit update itself?
No. The README states the script does not auto-update and that the installed version stays in place until you run menu option 8 or tcpfit update, which only checks and then asks whether to upgrade.
How do I undo the changes made by Kylin010/tcpfit?
Run tcpfit rollback, which writes the recorded values back item by item rather than restoring defaults. Swap created by harden is left alone unless you add --purge-swap.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kylin010-tcpfit)