# Bandwidth limiting without breaking ToS

**URL:** <https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874>\
**Category:** Node Operators\
**Tags:** online-score, bandwidth, router, audits, hardware\
**Created:** [October 7, 2026, 3:37pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874 "2026-10-07T15:37:39Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![hwm.land](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/hwm.land/32/1138_2.png) [@hwm.land](https://forum.storj.io/u/hwm.land)\
**Post date:** [October 7, 2026, 3:37pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/1 "2026-10-07T15:37:39Z")

</div>

> [@Rightsizing Storj Network Payout Rates](https://forum.storj.io/t/rightsizing-storj-network-payout-rates/32391/541):
>
> I can setup the base rate to be 30Mbps, which is within ToS (25 down + 5 up)

Are you sure it’ll not hurt audits/online score when `tc` starts dropping packets? Did you implement it? What are your results?

---

<div class="post-metadata">

**Author:** ![arrogantrabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/arrogantrabbit/32/11200_2.png) [@arrogantrabbit](https://forum.storj.io/u/arrogantrabbit)\
**Post date:** [October 7, 2026, 4:07pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/2 "2026-10-07T16:07:21Z")

</div>

> [@hwm.land](#):
>
> Are you sure it’ll not hurt audits/online score when `tc` starts dropping packets?

No; TCP is designed to use packet loss as a congestion signal and respond by backing off and retransmitting.

Yes, I did, it works rather well – credits get accumulated when load is lower, then spent when usage picks up. It’s pretty cool. Most of the time went into designign recovery procedure (ie if instance dies following bad OS update, I woudl need to recover it from backup, and apply current statistics and quotas (that are stored to external cloud storage every 5 min for this purpose).

---

<div class="post-metadata">

**Author:** ![alpharabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/alpharabbit/32/1129_2.png) [@alpharabbit](https://forum.storj.io/u/alpharabbit)\
**Post date:** [October 7, 2026, 4:49pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/3 "2026-10-07T16:49:07Z")

</div>

My internet lines are at the upload limit atm and I see online scores going down but audit is still ok.

---

<div class="post-metadata">

**Author:** ![arrogantrabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/arrogantrabbit/32/11200_2.png) [@arrogantrabbit](https://forum.storj.io/u/arrogantrabbit)\
**Post date:** [October 7, 2026, 5:19pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/4 "2026-10-07T17:19:17Z")

</div>

You probably have bufferbloat - important packets sit in queue forever and timeout.

Consider some sort of queue management – like fq\_codel – on your wan link.

If you use Ubiquiti gateways (and why would you use anything else? 😉 ) it’s built in, called SmartQueues.

PfSense has it also built in and OpenWRT has packages (sqm-scripts and luci-app-sqm)

---

<div class="post-metadata">

**Author:** ![alpharabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/alpharabbit/32/1129_2.png) [@alpharabbit](https://forum.storj.io/u/alpharabbit)\
**Post date:** [October 7, 2026, 5:41pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/5 "2026-10-07T17:41:27Z")

</div>

I have testet a lot with pfsense settings but no sort of queue management can magically overcome the missing bandwidth. I settled with just prioritizing the none storj traffic.

---

<div class="post-metadata">

**Author:** ![arrogantrabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/arrogantrabbit/32/11200_2.png) [@arrogantrabbit](https://forum.storj.io/u/arrogantrabbit)\
**Post date:** [October 7, 2026, 5:51pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/6 "2026-10-07T17:51:20Z")

</div>

> [@alpharabbit](#):
>
> I have testet a lot with pfsense settings but no

Then keep testing, until you make it work. because fq\_codel + HTB (which ubiquity is using) is absolutely magically overcomes missing bandwidth – latency goes back to below 10ms while you are fully saturating connection.

> [@alpharabbit](#):
>
> no sort of queue management can magically overcome the missing bandwidth.

I used to have 400down/12up (yes, twelve) internet for a while, it was saturated all the time – bandwidth graph was a straight line for _months_ (I like doing backups) – and this made it imperceptible.. I tried it on OpenWRT, got blown away, and bought USG3. This was my gateway drug to ubiquity ecosystem. Yes, it’s magic. (ok, math. Same thing)

I don’t know how to do it on pfSense – I tried it, and I absolutely despise the interface, I refused to use it.

> [@alpharabbit](#):
>
> prioritizing

This is a half-measure. F in FQ mean Fair. And it’s dynamic, unlike whatever static priorities you assign, manually and have to maintain

Edit, curiously, it’s (been rnamed?) now “Flow Queueing” not “Fair Queuing”: [RFC 8290: The Flow Queue CoDel Packet Scheduler and Active Queue Management Algorithm | RFC Editor](https://www.rfc-editor.org/info/rfc8290/)

> ```auto
> FQ-CoDel is a hybrid of DRR [DRR] and CoDel [RFC8289], with an
> optimisation for sparse flows similar to Shortest Queue First (SQF)
> [SQF] and DRR++ [DRRPP]. We call this "flow queueing" rather than
> "fair queueing", as flows that build a queue are treated differently
> from flows that do not.
> 
> ```

Even though the document still talks a lot about fairness.

---

<div class="post-metadata">

**Author:** ![alpharabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/alpharabbit/32/1129_2.png) [@alpharabbit](https://forum.storj.io/u/alpharabbit)\
**Post date:** [October 7, 2026, 6:20pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/7 "2026-10-07T18:20:47Z")

</div>

I have acceptable latency for none storj traffic and internet lines are already saturated with current pfsense settings. A “fair” approach can’t work in my opinion when the overload is massive and 90+ percent of all traffic is storj.

---

<div class="post-metadata">

**Author:** ![arrogantrabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/arrogantrabbit/32/11200_2.png) [@arrogantrabbit](https://forum.storj.io/u/arrogantrabbit)\
**Post date:** [October 7, 2026, 7:39pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/8 "2026-10-07T19:39:40Z")

</div>

What’s your upload bandwidth, and how many concurrent outgoing Storj transfers do you have when your online score starts dropping?

---

<div class="post-metadata">

**Author:** ![Pentium100](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/pentium100/32/6082_2.png) [@Pentium100](https://forum.storj.io/u/Pentium100)\
**Post date:** [October 15, 2026, 9:44am UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/9 "2026-10-15T09:44:41Z")

</div>

> [@alpharabbit](#):
>
> I have acceptable latency for none storj traffic and internet lines are already saturated with current pfsense settings.

You probably want to prioritize traffic instead of hard limiting it, but I do not know if pfSense can do it. I use pfSense in some places, but never had to use its shaping. Here’s how I do it on my Linux router for my backup connection (which only has about 11mbps upload).  
ext0.4093 is the interface that connects to that ISP. I skipped some classes that are specific for my uses.

```auto
tc qdisc del dev ext0.4093 root
tc qdisc add dev ext0.4093 root handle 10: htb default 106

tc class add dev ext0.4093 parent 10:0 classid 10:1 htb rate 10mbit ceil 11mbit burst 64k cburst 2k

#TCP ACK
tc class add dev ext0.4093 parent 10:1 classid 10:101 htb rate 1mbit ceil 11mbit burst 64k cburst 2k prio 1
tc qdisc add dev ext0.4093 parent 10:101 fq_codel
#ICMP
tc class add dev ext0.4093 parent 10:1 classid 10:103 htb rate 1mbit ceil 11mbit burst 64k cburst 2k prio 3
tc qdisc add dev ext0.4093 parent 10:103 fq_codel
#udp
tc class add dev ext0.4093 parent 10:1 classid 10:105 htb rate 1mbit ceil 11mbit burst 64k cburst 2k prio 5
tc qdisc add dev ext0.4093 parent 10:105 fq_codel
#default
tc class add dev ext0.4093 parent 10:1 classid 10:106 htb rate 1mbit ceil 11mbit burst 64k cburst 2k prio 6
tc qdisc add dev ext0.4093 parent 10:106 fq_codel
#Storj norm
tc class add dev ext0.4093 parent 10:1 classid 10:108 htb rate 1mbit ceil 11mbit burst 64k cburst 2k prio 8
tc qdisc add dev ext0.4093 parent 10:108 fq_codel

#filters
tc filter add dev ext0.4093 parent 10:0 prio 1 protocol ip u32

#TCP ACK 
# IHL = 5 (no options)
# length <=63B
# ACK flag and nothing else
tc filter add dev ext0.4093 parent 10:0 prio 1 protocol ip u32 \
match ip protocol 6 0xff \
match u8 0x05 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33 \
flowid 10:101

#ICMP
tc filter add dev ext0.4093 parent 10:0 prio 1 protocol ip u32 \
match ip protocol 0x01 FF \
flowid 10:103

#Storj norm
#TCP/UDP
#src port 42000
tc filter add dev ext0.4093 parent 10:0 prio 1 protocol ip u32 \
match ip protocol 6 0xff \
match ip sport 42000 FFFF \
flowid 10:108
tc filter add dev ext0.4093 parent 10:0 prio 1 protocol ip u32 \
match ip protocol 0x11 0xff \
match ip sport 42000 FFFF \
flowid 10:108

#UDP
tc filter add dev ext0.4093 parent 10:0 prio 1 protocol ip u32 \
match ip protocol 0x11 FF \
flowid 10:104

```

This makes TCP ACK packets the highest priority, followed by ICMP and then UDP packets. Storj node gets the lowest priority, so it can use whatever bandwidth is left from everything else.

The important part is to set the bandwidth limit slightly lower than what you get from the ISP.

It seems to work fine, the 10mbps upload is saturated but I can use other stuff without problems.

> [@arrogantrabbit](#):
>
> This is a half-measure. F in FQ mean Fair. And it’s dynamic, unlike whatever static priorities you assign, manually and have to maintain

Prioritizing works better in this case IMO. The reason is that, say, a video chat is more important that the Stroj traffic, so it should have higher priority. With just “fair queueing”, when stuff gets overloaded, everything slows down, but with priorities, the things that are more important remain responsive, while the less important things slow down.

---

<div class="post-metadata">

**Author:** ![hwm.land](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/hwm.land/32/1138_2.png) [@hwm.land](https://forum.storj.io/u/hwm.land)\
**Post date:** [October 15, 2026, 10:00am UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/10 "2026-10-15T10:00:26Z")

</div>

> [@Pentium100](#):
>
> You probably want to prioritize traffic instead of hard limiting it,

Well I think he wants _hard limiting it_, because of free quota on oracle.  
But it seems that heavy repair trafic is gone anyway, it falls as a stone ☹

---

<div class="post-metadata">

**Author:** ![Pentium100](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/pentium100/32/6082_2.png) [@Pentium100](https://forum.storj.io/u/Pentium100)\
**Post date:** [October 15, 2026, 10:16am UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/11 "2026-10-15T10:16:00Z")

</div>

If its only the node traffic going there then it is very easy - just a single class (I am sure there are other QDs that can do this, but I am used to htb, so I use it everywhere).

---

<div class="post-metadata">

**Author:** ![Roxor](https://storj.bcdn.literatehosting.com/letter_avatar/roxor/32/5_5575768a8748004e209b776fc1b2916d.png) [@Roxor](https://forum.storj.io/u/Roxor)\
**Post date:** [October 15, 2026, 2:17pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/12 "2026-10-15T14:17:31Z")

</div>

> [@hwm.land](#):
>
> But it seems that heavy repair trafic is gone anyway, it falls as a stone ☹

I think you’re right - but it was fun while it lasted! 🎉

---

<div class="post-metadata">

**Author:** ![alpharabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/alpharabbit/32/1129_2.png) [@alpharabbit](https://forum.storj.io/u/alpharabbit)\
**Post date:** [October 15, 2026, 2:53pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/13 "2026-10-15T14:53:53Z")

</div>

Egress chart (green) is not looking like slowdown. More like a temporary service outage… 🤔

 ![storj_day](https://storj-s3.bcdn.literatehosting.net/original/3X/9/a/9a5ddca05850c967e4944713a8c7f10c9ab3ad47.jpeg)

---

<div class="post-metadata">

**Author:** ![arrogantrabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/arrogantrabbit/32/11200_2.png) [@arrogantrabbit](https://forum.storj.io/u/arrogantrabbit)\
**Post date:** [October 15, 2026, 4:56pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/14 "2026-10-15T16:56:07Z")

</div>

> [@Pentium100](#):
>
> With just “fair queueing”, when stuff gets overloaded, everything slows down,

This is not entirely true. fq\_codel already gives preference to sparse flows – those that don’t maintain a standing queue. Bulk transfers normally have separate queues, so their backlog doesn’t sit ahead of every call packet. codel controls persistent queueing delay within those queues. This keeps video call responsive on a saturated link without explicitly prioritizing the application, while fqcodel controls the bottlenecked queue. This also works for long-running connections. A flow can return to the preferred queue list after its queue drains.

From RFC 8290, paragraph 1.3, in the end:

> .. it will effectively get priority over queues that do not empty out each round (a minor caveat is required here to protect against starvation, see below). Exactly how little data a flow has to send to keep its queue in this state is somewhat difficult to reason about, because it depends on both the egress link speed and the number of concurrent flows. However, in practice, many things that are beneficial to have prioritised for typical internet use (ACKs, DNS lookups, interactive Secure Shell (SSH), HTTP requests, Voice over IP (VoIP)) _tend_ to fall in this category, which is why FQ-CoDel performs so well for many practical applications. However, the implicitness of the prioritisation means that for applications that require guaranteed priority (for instance, multiplexing the network control plane over the network itself), explicit classification is still needed.

But I guess if storj traffic results in a lot of flows this can leave a video insufficient bandwidth, which will make it backlogged persistently and lose the sparse-flow treatment then explicit classification will help. When storj can do that on my connection – that would be a happy day for everyone 😃

But I don’t’ like manually classifying things unless I have it, and so far – I did not need to, even on slower connection, that was always saturated. I’m not sure if Unifi does some other magic in addition to fq\_codel though. They totally might.

---

<div class="post-metadata">

**Author:** ![Pentium100](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/pentium100/32/6082_2.png) [@Pentium100](https://forum.storj.io/u/Pentium100)\
**Post date:** [October 15, 2026, 6:05pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/15 "2026-10-15T18:05:17Z")

</div>

Good to know. Storj traffic does not saturate a normal connection, but it would saturate my backup connection right now (egress is about 15mbps), that’s why I use priorities on that connection. Priorities also help in case of similar looking streams. For example, if I’m uploading a large file somewhere, it should take priority over Storj, even though both would look similar as “bulk transfers”, but a video call should take priority over both.

---

<div class="post-metadata">

**Author:** ![Toyoo](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/toyoo/32/1126_2.png) [@Toyoo](https://forum.storj.io/u/Toyoo)\
**Post date:** [October 15, 2026, 7:48pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/16 "2026-10-15T19:48:21Z")

</div>

> [@arrogantrabbit](#):
>
> I used to have 400down/12up (yes, twelve) internet for a while, it was saturated all the time – bandwidth graph was a straight line for _months_ (I like doing backups)

Was it already with Storj traffic?

I wonder. fq\_codel considers each connection separately, and Storj has a large number of them. It cannot really act on short-lived connections, and most of connections Storj makes are short-lived. And even if a connection uploads/downloads more data, these connections on each own would be often pretty slow too, because the customer would also have to spread their traffic across many nodes—hence potentially being treated preferentially by fq\_codel.

This is a similar case to bittorrent’s LEDBAT traffic shaping. [This paper](https://conferences.sigcomm.org/co-next/2012/eproceedings/student/p25.pdf) describing the issue is even cited by fq\_codel’s [RFC8290](https://www.rfc-editor.org/rfc/rfc8290.html) acknowledging the issue.

So quite curious now how well does fq\_codel actually work with Storj…

---

<div class="post-metadata">

**Author:** ![arrogantrabbit](https://storj.bcdn.literatehosting.com/user_avatar/forum.storj.io/arrogantrabbit/32/11200_2.png) [@arrogantrabbit](https://forum.storj.io/u/arrogantrabbit)\
**Post date:** [October 15, 2026, 10:50pm UTC](https://forum.storj.io/t/bandwidth-limiting-without-breaking-tos/32874/17 "2026-10-15T22:50:13Z")

</div>

> [@Toyoo](#):
>
> Was it already with Storj traffic?

No, I think it was before storj, but with bit-torrent.

> [@Toyoo](#):
>
> It cannot really act on short-lived connections,

Codel cannot, but fq\_codel can. From the same rfc:

> Additionally, flow isolation radically improves the transient behaviour of the network when traffic or link characteristics change (e.g., when new flows start up or the link bandwidth changes); while CoDel itself can take a while to respond, FQ-CoDel reacts almost immediately.

I’m not sure it’s the same issue with LEBAT, I need to read that carefully, it seems it has to do AQM keeping delays below the level that makes LEDBAT back off.
