Security

Optimize Ubuntu VPS network performance in Vietnam for low-latency international connectivity

When your Ubuntu VPS sits in a Vietnam datacenter but your clients, APIs, or CI/CD runners live overseas, every millisecond of international latency is visible to the user. The default Ubuntu kernel is tuned for general-purpose workloads, not for long thin cross-border paths. You can recover a meaningful chunk of that latency with a handful of sysctl settings, a modern congestion control algorithm, and a properly sized socket buffer, without touching your provider's routing. This guide applies to an Ubuntu 24.04 LTS VPS with root access over SSH, and every change includes a verify step so you know it actually took effect.

Why a Vietnam VPS needs different network tuning

Traffic leaving Vietnam for international destinations crosses a domestic last mile, then one of the subsea cable systems, then whatever transit the far-end network uses. That path is long and often lossy. The default Linux TCP stack assumes a short, low-loss LAN path and keeps buffers small, which means a single dropped packet on a subsea leg can stall a transfer for a full retransmission timeout. For a Linux VPS serving international users, the fix is to raise buffers, acknowledge more aggressively, and pick a congestion control algorithm that recovers quickly from loss.

There is a second problem: bufferbloat. Intermediate routers on international paths buffer excess packets, so latency climbs exactly when you push traffic. Tuning the kernel does not eliminate bufferbloat on someone else's router, but it does make your VPS stop adding its own queuing delay on top. These settings are safe on a production host, but you should apply them one group at a time and re-test, rather than pasting everything blindly.

优化越南 VPS 的内核参数可显著降低国际链路的延迟与抖动。

Tuning kernel parameters on a Vietnam VPS can noticeably reduce latency and jitter on international paths.

Step 1 - Confirm the current network baseline

Before changing anything, measure where you start. Run a ping to a stable international target and record both the average and the variance. A 180 ms average with 40 ms of jitter tells a different story than a steady 90 ms.

ping -c 50 1.1.1.1 | tail -3

Also confirm the default congestion control and queueing discipline. Ubuntu 24.04 ships with a kernel that supports BBR, but it is not always enabled.

sysctl net.ipv4.tcp_congestion_control
sysctl net.core.default_qdisc

Typical output shows cubic for the first and pfifo_fast for the second. You will change both. Record the output of the ping test in a note; you will re-run it after the tuning to see the difference.

Step 2 - Enable TCP BBR and fq for congestion control

BBR is Google's congestion control algorithm and it is built into the Ubuntu 24.04 kernel. Unlike cubic, which treats packet loss as a signal to halve the sending rate, BBR models the actual bottleneck bandwidth and round-trip time. On international paths from Vietnam where loss is often sporadic rather than a sign of real congestion, BBR keeps throughput high without inflating latency. Pair it with the fq queueing discipline, which reduces bufferbloat on the sending side by pacing packets.

sudo tee /etc/sysctl.d/90-network-tuning.conf <<'EOF'
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sudo sysctl --system

The --system flag loads all files in /etc/sysctl.d/ in order, so your new file applies without a reboot. Verify that both settings took effect before moving on.

sysctl net.ipv4.tcp_congestion_control
sysctl net.core.default_qdisc

Expected output: net.ipv4.tcp_congestion_control = bbr and net.core.default_qdisc = fq. If you still see cubic, your kernel may not include BBR, which is unusual on 24.04; check with sudo modprobe tcp_bbr and re-run the sysctl command.

Step 3 - Raise socket buffers for long fat paths

The default receive buffer on Ubuntu is generous enough for LAN use but too small for a high-bandwidth path with a round-trip time above 100 ms. The TCP window needs to be at least the bandwidth-delay product, otherwise the sender stalls waiting for acknowledgments. For a 100 Mbps domestic link crossing to an international peer, a 200 ms RTT implies roughly 2.5 MB in flight; set the maximums well above that.

sudo tee -a /etc/sysctl.d/90-network-tuning.conf <<'EOF'
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_mtu_probing = 1
EOF
sudo sysctl --system

The three values in tcp_rmem are the minimum, default, and maximum. The kernel grows the buffer between the minimum and maximum based on the path, so leaving the default at 87380 is fine; the important part is the 16 MB ceiling. Setting tcp_mtu_probing to 1 lets the kernel discover a smaller MTU when a path drops large packets silently, which happens on some international routes and causes connections to hang for no visible reason.

Verify the new maximums are live:

sysctl net.core.rmem_max net.ipv4.tcp_rmem

Look for net.core.rmem_max = 16777216 in the output. If you run a workload that mostly sends large files, like a backup server or a GitLab instance, these buffers matter more than any other setting on this page.

Step 4 - Trim timeouts for faster failure detection

Default TCP keepalive timers assume you want to hold a dead connection open for two hours. On an international link where a subsea cable reroute can silently blackhole traffic, two hours is an eternity. Shortening these timers does not break healthy connections; it only makes the kernel notice a dead peer sooner and free the socket.

sudo tee -a /etc/sysctl.d/90-network-tuning.conf <<'EOF'
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_syn_backlog = 8192
EOF
sudo sysctl --system

With these values the kernel probes a dead peer after 60 seconds of inactivity, retries every 10 seconds, and gives up after 6 probes, so roughly two minutes to declare a connection dead instead of two hours. The SYN backlog bump helps when a flash of new connections arrives, which is common right after a cable incident reroutes traffic and clients reconnect en masse.

sysctl net.ipv4.tcp_keepalive_time

Output should read net.ipv4.tcp_keepalive_time = 60. A side effect worth knowing: if you run SSH and rely on long-lived idle sessions, the server will now drop them after roughly two minutes of silence unless your SSH client sends keepalives. Add ServerAliveInterval 30 to your local ~/.ssh/config if that affects you.

Step 5 - Confirm application sockets use the new buffers

Kernel-wide sysctls set the ceiling, but a busy service like Nginx or PostgreSQL can override the defaults per socket. For Nginx, set the listen socket options so accepted connections inherit the larger buffers. Open the main config and add the listen directive with the backlog and deferred accept flags.

sudo nano /etc/nginx/nginx.conf

Inside the http block, add these two lines if they are not already present:

listen backlog=4096 deferred;
sendfile on;
tcp_nopush on;
tcp_nodelay on;

The deferred flag tells the kernel not to complete the TCP handshake until the client sends its first request, which reduces the number of half-open sockets under a SYN flood. tcp_nodelay disables Nagle's algorithm, which matters for chatty APIs where a 40 ms delay per request segment is unacceptable. Verify the config and reload:

sudo nginx -t
sudo systemctl reload nginx

You want nginx: configuration file /etc/nginx/nginx.conf test is successful. If you run a reverse proxy or an Nginx reverse proxy setup on Ubuntu 24.04, these socket options apply to every upstream connection too.

Troubleshooting common issues after tuning

Three failures show up regularly after applying these settings. First, a service that was started before the sysctl change keeps old socket defaults until restarted. If Nginx or PostgreSQL still behaves as before, restart the service, do not just reload it: sudo systemctl restart nginx. Second, if throughput drops instead of rising, your provider's international path may be rate-limited below what the larger buffers expect; check with a single-stream iperf3 test rather than assuming the kernel is at fault. Third, if you see No such file or directory when loading the sysctl file, a typo in a key name is the cause. Run sudo sysctl --system and read the error line; it names the bad key.

During subsea cable maintenance, which remains a recurring event for Vietnam international connectivity, BBR will keep your transfers moving where cubic would stall. The kernel simply adapts faster to the rerouted, higher-loss path. Do not expect these settings to fix routing itself; if a cable is down, your traffic takes a longer path and latency rises for everyone, not just your VPS. What tuning fixes is the self-inflicted delay from small buffers and slow loss recovery.

Re-run the ping test from Step 1 and compare the jitter number. A drop from 40 ms of variance to 15 ms is a realistic, measurable win. Throughput on a single transfer should also climb under BBR because the algorithm stops halving the rate on every lost packet. If the numbers barely moved, your bottleneck is almost certainly the international transit itself, which no kernel setting changes.

FAQ

Does enabling TCP BBR work on any Ubuntu VPS in Vietnam?

BBR requires a kernel newer than 4.9, so every supported Ubuntu release, including 24.04 LTS, includes it. The module is tcp_bbr and loads on demand. If sysctl net.ipv4.tcp_congestion_control still shows cubic after applying the config, run sudo modprobe tcp_bbr and reload sysctl.

Will larger socket buffers waste memory on a small VPS?

No. The values in tcp_rmem and tcp_wmem are ceilings, not pre-allocations. The kernel only grows a buffer to match the path, so an idle VPS uses the same memory as before. A 2 GB RAM VPS can safely use the 16 MB maximums from this guide.

Can these settings reduce ping time to international servers?

No tuning changes the physical path your packets take. If your provider routes through a congested exchange, latency stays high. What these settings reduce is added queuing delay and slow loss recovery, which shows up as lower jitter and steadier throughput rather than a lower average ping.

Should I apply fq or fq_codel as the queueing discipline?

Use fq when you enable BBR, since BBR is designed to work with fair queueing. fq_codel targets bufferbloat on the sending side and pairs better with cubic. Since this guide enables BBR, stick with fq.

Related articles

越南 VPS 国际网络延迟优化要点

本文针对位于越南机房的 Ubuntu 服务器,介绍了降低国际链路延迟的内核调优方法。启用 BBR 拥塞控制算法与 fq 队列规则,可显著减少跨国传输中的丢包恢复时间。同时调高 TCP 接收与发送缓冲区上限,并缩短连接超时探测周期,有助于在海底光缆故障时快速恢复。每项调整均提供验证命令,适合需要稳定访问海外服务的越南业务使用。

Note: This guide is for general reference. Every system and infrastructure has its own specifics, so test each step in a safe environment and consult a qualified engineer before applying it in production.