Network speed limits and bandwidth usage
Set network speed limits on your VPS at the platform level through Virtualizor or inside the guest OS using Linux traffic control tools. This guide covers egress and ingress shaping, policing, and how to monitor bandwidth usage across both AlmaLinux and Ubuntu.
Network speed limits and bandwidth usage
You can cap a VPS’s network speed and track bandwidth in two places: at the platform level in Virtualizor, and inside the guest OS with Linux tools. Virtualizor can enforce per‑VPS caps and shows monthly usage. Inside Linux you can shape traffic with tc for smooth rate control or use nftables to rate‑limit by dropping excess packets.
Before you start
- Have a console open. When you change traffic control remotely you can cut off SSH. In Hostworld, you can open the VNC console for your VPS in Virtualizor from the client area. Keep it open while you test, or plan a timed rollback.
- Decide where to enforce the cap. Virtualizor can cap a VPS at the platform level and shows monthly bandwidth graphs. That is often the most reliable way to stay within an allowance. If you need per‑direction or per‑rule control inside the OS, use the tc or nftables methods below.
- Shaping vs policing. tc shapers such as TBF and HTB queue packets to deliver a configured rate. Policing drops packets above a rate and does not queue. Expect loss if you police rather than shape.
- Ingress specifics. Linux cannot shape ingress directly. To shape inbound traffic you redirect it to an ifb device, then shape on the ifb. Filters that hang off the ingress qdisc are attached with
parent ffff:, not with the bare wordingress. - Ubuntu firewall backend. Ubuntu uses nftables by default. The nftables systemd service is packaged but disabled by default. Ubuntu’s security docs advise not to mix native nftables with iptables or ufw rules at the same time.
- AlmaLinux 9 firewall backend. The RHEL 9 family uses nftables through firewalld, and firewalld manages that ruleset itself. The iptables backend is deprecated.
- Ubuntu 24.04 network config. NetworkManager now stores settings through Netplan. That does not stop you using dispatcher scripts to re‑apply tc at link‑up.
- Link‑level caps. ethtool can force a lower link speed. Both ends must support the setting. Forcing values that are not supported can flap or drop the link.
- Keep NetworkManager dispatcher scripts short. Long‑running or faulty scripts can delay interface activation.
Step 1: Use Hostworld’s Virtualizor controls first
Virtualizor, which you reach from the Hostworld client area, tracks per‑VPS bandwidth usage by month and supports per‑VPS network speed caps at the platform level. A platform cap is applied outside the guest, so it remains effective regardless of your OS settings. If you want a cap set or changed, open a support ticket and tell us the VPS and the rate you need. Use Virtualizor’s graphs to check your monthly usage trend after changes.
If you need finer control inside the VPS, continue with the steps below.
Step 2: Identify the interface and check a baseline
This shows per‑interface byte and packet counters so you can see current usage.
AlmaLinux 9
ip -s link
Ubuntu 24.04
ip -s link
This summarises socket activity, which can hint at busy protocols before you shape.
AlmaLinux 9
ss -s
Ubuntu 24.04
ss -s
Pick the interface you intend to manage, for example ens3 or eth0. In the commands below, replace DEV with your device name.
Step 3: Set an egress cap with tc TBF
This attaches a Token Bucket Filter shaper to the egress of your interface. It limits outbound traffic to a configured rate. burst is in bytes and allows short bursts. latency bounds queueing delay.
AlmaLinux 9
# Replace DEV and the rates to suit
tc qdisc replace dev DEV root tbf rate 50mbit burst 64kb latency 200ms
# Show the active qdisc on the interface
tc -s qdisc show dev DEV
Ubuntu 24.04
# Replace DEV and the rates to suit
tc qdisc replace dev DEV root tbf rate 50mbit burst 64kb latency 200ms
# Show the active qdisc on the interface
tc -s qdisc show dev DEV
The replace form is used here on purpose. It sets the root qdisc whether or not one is already present, so re‑running the command does not fail.
To remove the shaper and restore default queuing on egress:
AlmaLinux 9
tc qdisc del dev DEV root
Ubuntu 24.04
tc qdisc del dev DEV root
Step 4: Limit inbound traffic
Option A: Police ingress without shaping
This creates an ingress hook and applies a policing action that drops packets over the configured rate. It does not buffer or smooth traffic.
Read the conform-exceed argument carefully before you run this. It takes the exceed action, then a slash, then the action for traffic that conforms. drop/ok means drop what is over the rate and accept what is within it. If you give a single action with no slash, it applies to both cases, so conform-exceed drop drops every inbound packet and takes your VPS off the network. That is the one mistake in this article that will lock you out, which is why you want the VNC console open.
The ingress qdisc can only be attached once. If you have run Option A or Option B before, the add will fail with “File exists”, so clear any existing one first.
AlmaLinux 9
# Check whether an ingress qdisc is already attached
tc qdisc show dev DEV ingress
# Remove any existing one, then attach the special ingress qdisc
tc qdisc del dev DEV ingress 2>/dev/null
tc qdisc add dev DEV ingress
# Match all packets on ingress and police to 50 Mbit with a 64 KB burst
tc filter add dev DEV parent ffff: matchall police rate 50mbit burst 64kb conform-exceed drop/ok
Ubuntu 24.04
# Check whether an ingress qdisc is already attached
tc qdisc show dev DEV ingress
# Remove any existing one, then attach the special ingress qdisc
tc qdisc del dev DEV ingress 2>/dev/null
tc qdisc add dev DEV ingress
# Match all packets on ingress and police to 50 Mbit with a 64 KB burst
tc filter add dev DEV parent ffff: matchall police rate 50mbit burst 64kb conform-exceed drop/ok
To remove the ingress policer and qdisc:
AlmaLinux 9
tc filter del dev DEV parent ffff:
tc qdisc del dev DEV ingress
Ubuntu 24.04
tc filter del dev DEV parent ffff:
tc qdisc del dev DEV ingress
Option B: Shape ingress using an ifb device
This redirects ingress to an Intermediate Functional Block device, then applies a TBF shaper to that ifb. That gives real shaping for inbound traffic.
AlmaLinux 9
# Load the ifb kernel module
modprobe ifb
# Create and bring up an ifb device
ip link add ifb0 type ifb
ip link set dev ifb0 up
# Clear any existing ingress qdisc, then attach one to the real interface
tc qdisc del dev DEV ingress 2>/dev/null
tc qdisc add dev DEV ingress
# Redirect all ingress to ifb0
tc filter add dev DEV parent ffff: matchall action mirred egress redirect dev ifb0
# Shape on the ifb as if it were egress
tc qdisc replace dev ifb0 root tbf rate 50mbit burst 64kb latency 200ms
# Verify the shaper
tc -s qdisc show dev ifb0
Ubuntu 24.04
# Load the ifb kernel module
modprobe ifb
# Create and bring up an ifb device
ip link add ifb0 type ifb
ip link set dev ifb0 up
# Clear any existing ingress qdisc, then attach one to the real interface
tc qdisc del dev DEV ingress 2>/dev/null
tc qdisc add dev DEV ingress
# Redirect all ingress to ifb0
tc filter add dev DEV parent ffff: matchall action mirred egress redirect dev ifb0
# Shape on the ifb as if it were egress
tc qdisc replace dev ifb0 root tbf rate 50mbit burst 64kb latency 200ms
# Verify the shaper
tc -s qdisc show dev ifb0
To undo the ifb setup:
AlmaLinux 9
tc qdisc del dev ifb0 root
tc filter del dev DEV parent ffff:
tc qdisc del dev DEV ingress
ip link del ifb0
Ubuntu 24.04
tc qdisc del dev ifb0 root
tc filter del dev DEV parent ffff:
tc qdisc del dev DEV ingress
ip link del ifb0
Step 5: Use HTB to shape with a rate and a ceiling
This sets a Hierarchical Token Bucket on egress with a default class that has a guaranteed rate and an optional ceiling. This is useful when you want a hard cap with some burst up to a higher ceiling. The example below makes all egress use the default class.
AlmaLinux 9
# Root HTB with a default class 1:10
tc qdisc replace dev DEV root handle 1: htb default 10
# Create the default class with guaranteed 50 Mbit and ceiling 60 Mbit
tc class replace dev DEV parent 1: classid 1:10 htb rate 50mbit ceil 60mbit burst 64kb
# Show HTB classes and stats
tc -s class show dev DEV
Ubuntu 24.04
# Root HTB with a default class 1:10
tc qdisc replace dev DEV root handle 1: htb default 10
# Create the default class with guaranteed 50 Mbit and ceiling 60 Mbit
tc class replace dev DEV parent 1: classid 1:10 htb rate 50mbit ceil 60mbit burst 64kb
# Show HTB classes and stats
tc -s class show dev DEV
To remove HTB from egress:
AlmaLinux 9
tc qdisc del dev DEV root
Ubuntu 24.04
tc qdisc del dev DEV root
Step 6: Apply a quick drop‑based cap with nftables
This adds an nftables rule that drops traffic when it exceeds a configured byte rate. It is policing, not shaping. The example limits egress on DEV in the output hook.
AlmaLinux 9
# Create a dedicated table and chain
nft add table inet hostworldlimit
nft add chain inet hostworldlimit output { type filter hook output priority 0; policy accept; }
# Drop egress above 10 MB per second on DEV
nft add rule inet hostworldlimit output oifname "DEV" limit rate over 10 mbytes/second counter drop
# Inspect rules
nft list ruleset
Ubuntu 24.04
# Create a dedicated table and chain
nft add table inet hostworldlimit
nft add chain inet hostworldlimit output { type filter hook output priority 0; policy accept; }
# Drop egress above 10 MB per second on DEV
nft add rule inet hostworldlimit output oifname "DEV" limit rate over 10 mbytes/second counter drop
# Inspect rules
nft list ruleset
To remove the example table and all its rules:
AlmaLinux 9
nft delete table inet hostworldlimit
Ubuntu 24.04
nft delete table inet hostworldlimit
Test nft rules interactively first. On Ubuntu, do not mix native nftables with iptables or ufw. When you are satisfied, you can load rules from /etc/nftables.conf at boot by enabling the nftables service.
AlmaLinux 9
Do not enable a separate nftables service here if firewalld is running. On AlmaLinux 9 the firewall stack uses nftables through firewalld, and firewalld manages that ruleset itself, so a second service loading /etc/nftables.conf can conflict with it. Either treat the nft commands above as a temporary, manually applied measure, or manage the cap through firewalld’s own configuration. If you are not sure which applies to your VPS, open a support ticket and we will look at it with you.
Ubuntu 24.04
# Enable nftables to load /etc/nftables.conf at boot
systemctl enable --now nftables
Step 7: Make your tc changes persist across reboots
Persist tc with NetworkManager’s dispatcher
This creates a dispatcher script that applies your tc configuration when NetworkManager brings an interface up. NetworkManager waits for pre‑up scripts before marking the interface active.
AlmaLinux 9
cat >/etc/NetworkManager/dispatcher.d/10-tc-shaper <<'EOF'
#!/bin/sh
# $1 is the interface, $2 is the state
DEV="DEV"
case "$2" in
pre-up|up)
if [ "$1" = "$DEV" ]; then
# Egress TBF
tc qdisc replace dev "$DEV" root tbf rate 50mbit burst 64kb latency 200ms
# Ingress shaping via ifb (optional)
# modprobe ifb 2>/dev/null || true
# ip link show ifb0 >/dev/null 2>&1 || ip link add ifb0 type ifb
# ip link set dev ifb0 up
# tc qdisc del dev "$DEV" ingress 2>/dev/null || true
# tc qdisc add dev "$DEV" ingress
# tc filter replace dev "$DEV" parent ffff: matchall action mirred egress redirect dev ifb0
# tc qdisc replace dev ifb0 root tbf rate 50mbit burst 64kb latency 200ms
fi
;;
esac
EOF
chmod +x /etc/NetworkManager/dispatcher.d/10-tc-shaper
Ubuntu 24.04
cat >/etc/NetworkManager/dispatcher.d/10-tc-shaper <<'EOF'
#!/bin/sh
# $1 is the interface, $2 is the state
DEV="DEV"
case "$2" in
pre-up|up)
if [ "$1" = "$DEV" ]; then
# Egress TBF
tc qdisc replace dev "$DEV" root tbf rate 50mbit burst 64kb latency 200ms
# Ingress shaping via ifb (optional)
# modprobe ifb 2>/dev/null || true
# ip link show ifb0 >/dev/null 2>&1 || ip link add ifb0 type ifb
# ip link set dev ifb0 up
# tc qdisc del dev "$DEV" ingress 2>/dev/null || true
# tc qdisc add dev "$DEV" ingress
# tc filter replace dev "$DEV" parent ffff: matchall action mirred egress redirect dev ifb0
# tc qdisc replace dev ifb0 root tbf rate 50mbit burst 64kb latency 200ms
fi
;;
esac
EOF
chmod +x /etc/NetworkManager/dispatcher.d/10-tc-shaper
Replace DEV with your interface name before saving. Bring an interface up in a maintenance window to test. Keep scripts short so NetworkManager is not delayed.
Persist tc with systemd‑networkd
If your system uses systemd‑networkd, you can declare traffic control in .network files. systemd.network supports qdisc sections such as [TokenBucketFilter], with Rate, BurstBytes, LimitBytes, LatencySec and Parent. Parent belongs inside the qdisc section itself, not in a section of its own.
Watch the units. Rate here is in bytes per second by default, unlike the tc examples above which are in bits. A 50 Mbit/s cap is 6250000 bytes per second, so the value below matches the rest of this article. Check systemd.network(5) on your system for the exact syntax and accepted suffixes before you rely on it.
[Match]
Name=DEV
[TokenBucketFilter]
Parent=root
Rate=6250000
BurstBytes=65536
LatencySec=200ms
Apply this in your existing .network file for the interface. Only use this route if systemd‑networkd already manages your device.
Step 8: Monitor bandwidth usage and live rates
This shows current kernel counters for your interface. It is low overhead and always available.
AlmaLinux 9
ip -s link show dev DEV
Ubuntu 24.04
ip -s link show dev DEV
This prints a live summary of sockets to spot heavy protocol use.
AlmaLinux 9
ss -s
Ubuntu 24.04
ss -s
For live rate views by host or interface, these tools are helpful. Install them from your distribution and run as below.
- vnStat live mode on an interface:
AlmaLinux 9
vnstat -l -i DEV
Ubuntu 24.04
vnstat -l -i DEV
- iftop showing conversations on an interface:
AlmaLinux 9
iftop -i DEV
Ubuntu 24.04
iftop -i DEV
- bmon for per‑interface rates:
AlmaLinux 9
bmon
Ubuntu 24.04
bmon
- nload to graph a single interface:
AlmaLinux 9
nload DEV
Ubuntu 24.04
nload DEV
What next
- If you want a VPS‑wide cap or help interpreting your Virtualizor graphs, open a support ticket and we will look at the best rate for your workload.
- Browse more topics in our VPS guides. Our UK VPS run from our own data centre in Maidenhead, Berkshire, and if you need more capacity, open a support ticket and we will size it with you.
Common questions
Should I shape or police?
Shape when you want smooth delivery at a target rate. TBF and HTB queue packets to meet the rate. Police when you want to hard‑limit with packet drops above a rate and you can tolerate loss. nftables limits and tc police are both policing. Do not expect them to smooth traffic.
Can I shape inbound traffic without an ifb?
No. Without ifb you can only police ingress to a rate and drop above it. To shape inbound traffic you must redirect ingress to an ifb and apply a shaper on the ifb device.
Will these tc settings survive a reboot?
No. tc changes are in‑memory. Use a NetworkManager dispatcher script or systemd‑networkd configuration to re‑apply on interface bring‑up. Keep a console session open when you test persistence so you can remove a bad rule.
Can I limit by bytes per second with the firewall?
Yes. nftables can match a byte rate per rule using a token bucket and a burst. It drops packets when the rule’s rate or quota is exceeded. This is not shaping and can cause drops during bursts. Load rules from /etc/nftables.conf with the nftables service when you are satisfied. On Ubuntu, do not mix native nftables with iptables or ufw rules.
What about CAKE or other advanced qdiscs on AlmaLinux 9?
Many EL9‑based kernels include the sch_cake module, which provides advanced shaping and queue management. Availability depends on the exact kernel build. Check your kernel for the module before you plan around it.
Is forcing a lower link speed with ethtool a good idea?
It is rarely the right first choice. ethtool can force a link speed and duplex, but both ends must support the setting. If they do not, the link can flap or drop. Prefer shaping or a Virtualizor platform cap. Use a link‑speed cap only when you have confirmed support on both ends and can take an outage.
I lost SSH after adding a limit. What do I do?
Use the VNC console in Virtualizor to remove the rule you added. If you need help, open a support ticket and tell us what you changed and when. We will help you recover access.