Introduction
VMs configured with jumbo MTU (9000) may experience TLS handshake timeouts or stalled downloads when connecting to external endpoints over the public internet.
This happens because the path to external destinations uses a smaller MTU (1500), and oversized packets are silently dropped. The TCP handshake completes normally because those packets are small — the issue only appears when the first large payload (e.g., a TLS record) exceeds the path MTU, which is why the connection appears to hang after establishing. Jumbo MTU is intended for VM-to-VM traffic within the same virtual network. For traffic destined to the public internet, standard MTU (1500) should be used.
This guide walks you through diagnosing the issue and applying the fix.
Prerequisites
- SSH Access to the Affected VM
-
sudoPrivileges on the VM
Instructions
-
Check your current MTU
Run the following to see the MTU on your network interfaces:
$ ip link show
Look for the interface used for external traffic (e.g.,
ens3,ens7). If the MTU is9000, this is likely the cause. -
Check the path MTU to your destination
Use
tracepathto discover the actual MTU supported along the network path:$ tracepath <destination_ip>
If the output shows
pmtu 1500(or lower) at an intermediate hop while your interface is set to 9000, the mismatch confirms the issue.You can also test directly with
curl:$ curl -sk https://<destination> --max-time 30 -o /dev/null -w "tcp_connect=%{time_connect}s tls=%{time_appconnect}s http_code=%{http_code}\n"If
tcp_connectshows a normal time buttlsshows0.000000sand the request times out, the TLS handshake is hanging due to oversized packets being dropped. -
Lower the MTU on the interface
Option A: Set the interface MTU to 1500 (recommended)
This is the simplest fix and is recommended for most workloads. Modern NIC offloads (GRO/TSO) handle segmentation in hardware, so lowering the MTU has no measurable impact on performance for typical workloads.
$ sudo ip link set dev <interface> mtu 1500
Replace
<interface>with your interface name (e.g.,ens7).Option B: Per-route override (specific destinations only)
If you need to keep jumbo MTU for internal traffic but fix connectivity to specific external destinations:
$ sudo ip route replace <destination_ip>/32 via <gateway_ip> dev <interface> mtu 1400
💡 Tip: The per-route MTU is set to 1400 (100 bytes below the standard 1500 path MTU) to leave headroom for encapsulation overhead such as VLAN tags, VXLAN, or GRE headers that may be present on the network path.
Find your default gateway with:
$ ip route | awk '/default/ {print $3; exit}' -
Verify connectivity
Test that TLS connections now complete:
$ curl -sk https://<destination> --max-time 10 -o /dev/null -w "tcp_connect=%{time_connect}s tls=%{time_appconnect}s http_code=%{http_code}\n"If the request returns a response instead of hanging, the fix is working.
-
Make the change persistent
The above command is runtime only and will not survive a reboot. To persist the change, add the following to your VM's startup script at
/usr/local/bin/crusoe/startup.sh:#!/bin/bash ip link set dev <interface> mtu 1500
Replace
<interface>with your interface name (e.g.,ens7). If you're creating a new VM, you can pass the script at creation time:crusoe compute vms create \ --name my-vm \ --type <vm-type> \ --keyfile ~/.ssh/id_ed25519.pub \ --startup-script ~/path/to/set-mtu.shFor more details, see Managing lifecycle scripts.
Example
A VM in eu-iceland1-a with MTU 9000 on ens3 cannot complete a TLS handshake to an external endpoint.
First, confirm the interface MTU is 9000:
ubuntu@<hostname>:~$ ip link show .... 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT.... ....
Attempt a TLS connection to an external endpoint:
ubuntu@<hostname>:~$ curl -sk https://<destination-ip> --max-time 30 -o /dev/null \
> -w "tcp_connect=%{time_connect}s tls=%{time_appconnect}s http_code=%{http_code}\n"
tcp_connect=0.045110s tls=0.000000s http_code=000Notice that tcp_connect succeeded (0.045s), but tls is 0.000000s and http_code is 000 — the TLS handshake never completed. This is the signature of the PMTU issue.
After setting MTU to 1500, the same endpoint works:
ubuntu@<hostname>:~$ sudo ip link set dev ens3 mtu 1500
ubuntu@<hostname>:~$ curl -sk https://<destination-ip> --max-time 30 -o /dev/null \
> -w "tcp_connect=%{time_connect}s tls=%{time_appconnect}s http_code=%{http_code}\n"
tcp_connect=0.047309s tls=0.128651s http_code=200Both tls (0.128s) and http_code (200) now show a successful connection.
For comparison, some endpoints like Google proactively clamp their MSS and work even with MTU 9000:
ubuntu@<hostname>:~$ ip link show
....
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT....
....
ubuntu@<hostname>:~$ curl -sk https://www.google.com --max-time 30 -o /dev/null \
> -w "tcp_connect=%{time_connect}s tls=%{time_appconnect}s http_code=%{http_code}\n"
tcp_connect=0.015270s tls=0.025650s http_code=200This is why the issue may appear to affect only certain destinations; it depends on whether the remote server clamps its MSS independently.
Troubleshooting
Still hanging after lowering MTU to 1500? If the issue persists, please reach out to Crusoe Cloud Support with the output of ip link show, tracepath <destination_ip>, and the curl test from Step 2.
Only certain destinations affected? Use the per-route override (Step 3) to target specific IPs without changing the interface MTU for all traffic.
Issue returns after reboot? The runtime change was not persisted. See Step 5 to make it permanent.