<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://sa.net/</id>
    <title>Riven Cloud</title>
    <updated>2026-07-14T05:54:43.391Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <author>
        <name>Riven Cloud OÜ</name>
        <email>sales@riven.cloud</email>
        <uri>https://sa.net/</uri>
    </author>
    <link rel="alternate" href="https://sa.net/"/>
    <link rel="self" href="https://sa.net/atom.xml"/>
    <subtitle>Riven Cloud runs premium KVM VPS in Tokyo and Singapore with top-tier three-network China-return route optimization — CTGNet (formerly China Telecom CN2 GIA), China Unicom Premium (CUP, AS9929 / AS10099), and China Mobile International N2 (CMIN2).</subtitle>
    <rights>© 2026 Riven Cloud OÜ</rights>
    <entry>
        <title type="html"><![CDATA[How to self-host RustDesk with Docker for China remote support]]></title>
        <id>https://sa.net/blog/self-host-rustdesk-china-remote-support/</id>
        <link href="https://sa.net/blog/self-host-rustdesk-china-remote-support/"/>
        <updated>2026-07-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A Docker tutorial for running RustDesk Server OSS as a Sunlogin cross-border alternative on a Tokyo VPS.]]></summary>
        <content type="html"><![CDATA[<p>On July 13, 2026, the Sunlogin client quoted us <strong>¥188 per month</strong> for cross-border remote control from Japan into mainland China. That ¥188 figure was an in-client, point-in-time quote. Sunlogin’s <a href="https://sunlogin.oray.com/price" title="public pricing page" target="_blank" rel="noopener noreferrer">public pricing page</a> did not list it when we checked, so it should not be read as a universal public price.</p>
<p>We needed occasional support sessions, not a subscription. We therefore self-hosted RustDesk Server OSS on an existing Riven Cloud Tokyo VPS while keeping the familiar remote-support workflow for the person receiving help.</p>
<h2 id="why-self-host-rustdesk">Why self-host RustDesk?<a href="#why-self-host-rustdesk" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Self-hosting gives the operator control of the server identity and relay path. RustDesk generates an Ed25519 key pair when <code>hbbs</code> first starts. The public key identifies and authenticates the self-hosted server to clients configured with that key. It is not a password, secret, or access-control list. Give clients only the public key and never expose the private <code>id_ed25519</code> file.</p>
<p>RustDesk sessions are end-to-end encrypted. A relay carries encrypted session traffic rather than an unencrypted desktop stream. With self-hosting, even that encrypted relay traffic stays on infrastructure we control instead of passing through a third-party relay.</p>
<p>RustDesk Server OSS also has no membership tiers, device-count limits, or per-feature paywalls. It provides the core ID and relay services without the web console, account management, and other administrative features offered by RustDesk Server Pro.</p>
<p>Relay placement is another practical benefit. We can choose the location and carrier path instead of accepting whichever relay the vendor assigns. This matters when a direct peer-to-peer connection cannot be established and the desktop session must cross the relay in both directions.</p>
<p>SSH, WireGuard, and Tailscale are excellent tools for machines and users we administer. They were wrong for this case because the remote party was a non-technical third party. The workflow needed to remain: install the client, share the ID, and approve the session. Requiring a tunnel would have created a second support job before we could address the first one.</p>
<h2 id="how-do-you-install-rustdesk-server-oss-with-docker">How do you install RustDesk Server OSS with Docker?<a href="#how-do-you-install-rustdesk-server-oss-with-docker" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The <a href="https://rustdesk.com/docs/en/self-host/rustdesk-server-oss/install/" title="official RustDesk Server OSS installation guide" target="_blank" rel="noopener noreferrer">official RustDesk Server OSS installation guide</a> recommends Docker for most deployments. The method below follows that guide and the current <a href="https://rustdesk.com/docs/en/self-host/rustdesk-server-oss/docker/" title="Docker documentation" target="_blank" rel="noopener noreferrer">Docker documentation</a> for a portable Compose deployment.</p>
<h3 id="check-the-prerequisites">Check the prerequisites<a href="#check-the-prerequisites" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>Use a Linux VPS with a public IPv4 address. Dual-stack IPv4 and IPv6 is preferred when both client networks support it. You also need <code>sudo</code> or root access and enough firewall control to expose the RustDesk ports.</p>
<p>A DNS hostname is optional but recommended. The examples use <code>rustdesk.example.com</code>; replace it with your own hostname. A public IP address also works, but a hostname is easier to move to another server later.</p>
<h3 id="install-docker-and-start-the-services">Install Docker and start the services<a href="#install-docker-and-start-the-services" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>Create a working directory so that the Compose file and persistent server data stay together:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">mkdir</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> ~/rustdesk-server</span></span>
<span class="line"><span style="color:#79B8FF">cd</span><span style="color:#9ECBFF"> ~/rustdesk-server</span></span></code></pre>
<p>Install Docker with the convenience installer used by the official documentation. Operators who already have a working Docker Engine and Compose plugin can skip this command:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">bash</span><span style="color:#9ECBFF"> &lt;(</span><span style="color:#B392F0">wget</span><span style="color:#79B8FF"> -qO-</span><span style="color:#9ECBFF"> https://get.docker.com)</span></span></code></pre>
<p>Download the official Compose file, then start both services:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">wget</span><span style="color:#9ECBFF"> https://rustdesk.com/oss.yml</span><span style="color:#79B8FF"> -O</span><span style="color:#9ECBFF"> compose.yml</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> docker</span><span style="color:#9ECBFF"> compose</span><span style="color:#9ECBFF"> up</span><span style="color:#79B8FF"> -d</span></span></code></pre>
<p>At the time of writing, the live <code>oss.yml</code> starts <code>hbbs</code> and <code>hbbr</code> from <code>rustdesk/rustdesk-server:latest</code>. Both containers mount <code>./data:/root</code>, use host networking, and restart with the <code>unless-stopped</code> policy.</p>

















<table><thead><tr><th>Service</th><th>Role</th></tr></thead><tbody><tr><td><code>hbbs</code></td><td>ID registration, rendezvous, signaling, and NAT traversal</td></tr><tr><td><code>hbbr</code></td><td>Encrypted session relay when direct hole punching fails</td></tr></tbody></table>
<p>Host networking means the processes listen directly on the VPS network stack. Check that both containers are running and inspect the <code>hbbs</code> startup output:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> docker</span><span style="color:#9ECBFF"> compose</span><span style="color:#9ECBFF"> ps</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> docker</span><span style="color:#9ECBFF"> compose</span><span style="color:#9ECBFF"> logs</span><span style="color:#79B8FF"> --tail=100</span><span style="color:#9ECBFF"> hbbs</span></span></code></pre>
<h3 id="open-the-firewall">Open the firewall<a href="#open-the-firewall" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>The official guide gives this simple UFW example:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 21114:21119/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 21116/udp</span></span></code></pre>
<p>The range is broader than the minimum RustDesk Server OSS set. Port <code>21114/tcp</code> serves the Pro web console and is not required by OSS. Port <code>21115/tcp</code> is used for the NAT type test. Port <code>21116/tcp</code> handles connections and TCP hole punching, while <code>21116/udp</code> handles ID registration and heartbeat traffic. Port <code>21117/tcp</code> carries relay sessions. Ports <code>21118/tcp</code> and <code>21119/tcp</code> support web clients and are optional when web-client access is unused.</p>
<p>Port <code>21116</code> must be allowed over both TCP and UDP. A tighter OSS policy can omit <code>21114/tcp</code> and, when appropriate, the two web-client ports. Mirror the chosen rules in any cloud firewall or security group outside the VPS. If the service is reachable over IPv6, verify that UFW created matching IPv6 rules rather than checking only the IPv4 table.</p>
<h3 id="retrieve-the-public-key-safely">Retrieve the public key safely<a href="#retrieve-the-public-key-safely" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>The downloaded Compose file mounts the host’s <code>./data</code> directory at <code>/root</code> inside both containers. After the first start, the host-side public key is therefore normally <code>./data/id_ed25519.pub</code>.</p>
<p>File layout can vary with the server version or deployment method. Find public-key files in the persistent directory if the expected path is absent:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> find</span><span style="color:#9ECBFF"> ./data</span><span style="color:#79B8FF"> -maxdepth</span><span style="color:#79B8FF"> 2</span><span style="color:#79B8FF"> -name</span><span style="color:#9ECBFF"> &#39;*.pub&#39;</span><span style="color:#79B8FF"> -type</span><span style="color:#9ECBFF"> f</span><span style="color:#79B8FF"> -print</span></span></code></pre>
<p>Read the expected public key with:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> cat</span><span style="color:#9ECBFF"> ./data/id_ed25519.pub</span></span></code></pre>
<p>The <code>hbbs</code> log can also show the generated key and help diagnose a different data layout:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> docker</span><span style="color:#9ECBFF"> compose</span><span style="color:#9ECBFF"> logs</span><span style="color:#9ECBFF"> hbbs</span></span></code></pre>
<p>Copy only the content of <code>id_ed25519.pub</code> into client configuration. Never share, publish, or paste <code>id_ed25519</code>, which is the server’s private key. Back up the persistent data directory securely because replacing the private key changes the server identity expected by configured clients.</p>
<h3 id="configure-the-clients">Configure the clients<a href="#configure-the-clients" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>On each RustDesk client, open <strong>Settings &gt; Network</strong> and set:</p>
<ul>
<li><strong>ID Server:</strong> <code>rustdesk.example.com</code> or your public IP address</li>
<li><strong>Key:</strong> the content of <code>id_ed25519.pub</code></li>
<li><strong>Relay Server:</strong> leave blank</li>
<li><strong>API Server:</strong> leave blank</li>
</ul>
<p>Both ends of the session need the self-hosted ID server and public key. <code>hbbs</code> advertises the associated <code>hbbr</code> relay automatically, so a separate relay value is unnecessary. The API field is for Pro features and remains blank for this OSS setup.</p>
<h3 id="verify-a-real-client-to-client-session">Verify a real client-to-client session<a href="#verify-a-real-client-to-client-session" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>Test between two clients on different networks rather than stopping after the containers report healthy. Confirm that both clients receive IDs through the new server, connect, and can exchange screen updates, keyboard and mouse input, and clipboard content.</p>
<p>In our actual test, Linux and Windows clients completed a real relayed session. Screen, keyboard and mouse input, and clipboard all worked. Direct hole punching failed for that test, so <code>hbbr</code> relayed the session. One successful session is an operational check, not a controlled network benchmark, and we are not using it to claim a latency figure.</p>
<p>The official installation guide says CPU and memory requirements are minimal. It estimates roughly <strong>30 KB/s to 3 MB/s</strong> for a relayed 1920×1080 session, depending on resolution and screen activity, with office work around <strong>100 KB/s</strong>. These are broad upstream estimates, not capacity or performance guarantees. Size transfer allowance and monitoring for your own concurrency and usage pattern.</p>
<h2 id="why-use-a-tokyo-vps-for-support-into-mainland-china">Why use a Tokyo VPS for support into mainland China?<a href="#why-use-a-tokyo-vps-for-support-into-mainland-china" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>A RustDesk relay is more of a network workload than a compute workload. Once the small CPU and memory requirement is met, adding vCPU does not repair a poor return path. Relay placement matters because a failed direct connection sends the interactive session through <code>hbbr</code>.</p>
<p>This is Riven Cloud’s own blog, and we sell the VPS used for this deployment. Our Tokyo network has carrier-specific paths for the three major mainland China access networks:</p>
<ul>
<li>China Telecom: <strong>CTGNet, formerly China Telecom CN2 GIA, AS23764 / AS4809</strong></li>
<li>China Unicom: <strong>CUP, China Unicom Premium, AS9929 / AS10099</strong></li>
<li>China Mobile: <strong>CMIN2, China Mobile International N2, AS58807</strong></li>
</ul>
<p>Our <a href="https://sa.net/blog/what-are-china-optimized-routes/" title="China-optimized routes explainer">China-optimized routes explainer</a> describes what those names mean and how to inspect the path. Operators should test from the networks that will actually use the service. The <a href="https://tok-premium.lg.xtom.com/" title="Tokyo Looking Glass" target="_blank" rel="noopener noreferrer">Tokyo Looking Glass</a> provides a starting point for ping and traceroute checks, but testing from the client access network remains important.</p>
<p>Performance depends on the access carrier, province, last mile, time of day, and whether RustDesk establishes a direct connection. A direct connection may bypass the relay workload entirely. A relayed session takes the server path, but no single Tokyo test proves how every mainland China access line will behave.</p>
<h2 id="when-is-self-hosting-not-worth-it">When is self-hosting not worth it?<a href="#when-is-self-hosting-not-worth-it" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>One-off users and operators unwilling to maintain updates, firewall policy, keys, and monitoring should use a hosted remote-support vendor. That fee buys less operational responsibility.</p>
<p>Self-hosting fits better when a suitable VPS already exists, support sessions recur, infrastructure control matters, or the workload needs a specific location and carrier path. The calculation should include server cost, transfer, and operator time rather than comparing only two monthly prices.</p>
<p>Test the <a href="https://tok-premium.lg.xtom.com/" title="Tokyo route" target="_blank" rel="noopener noreferrer">Tokyo route</a> from the networks that matter, then compare <a href="https://sa.net/pricing/" title="Riven Cloud VPS pricing">Riven Cloud VPS pricing</a> with the subscription cost and maintenance burden being replaced.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="RustDesk" term="RustDesk"/>
        <category label="China Connectivity" term="China Connectivity"/>
        <category label="VPS" term="VPS"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Nginx vs Apache vs Caddy: How to Choose a Web Server in 2026]]></title>
        <id>https://sa.net/blog/nginx-vs-apache-vs-caddy/</id>
        <link href="https://sa.net/blog/nginx-vs-apache-vs-caddy/"/>
        <updated>2026-07-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[In 2026, TLS certificates are headed for 47-day lifetimes; choosing Nginx, Apache, or Caddy means weighing ACME, HTTP/3, and control.]]></summary>
        <content type="html"><![CDATA[<p>The old Nginx vs Apache vs Caddy debate usually starts with benchmark charts. In 2026, that is the wrong place to start.</p>
<p>The CA/Browser Forum approved <a href="https://cabforum.org/2025/04/11/ballot-sc081v3-introduce-schedule-of-reducing-validity-and-data-reuse-periods/" title="Ballot SC-081v3" target="_blank" rel="noopener noreferrer">Ballot SC-081v3</a>, which sets a schedule for reducing public TLS certificate maximum validity periods. The ballot describes a reduction that starts in March 2026 and ends in March 2029 at 47 days. DigiCert’s explainer gives the operational dates in plain form: <a href="https://www.digicert.com/blog/tls-certificate-lifetimes-will-officially-reduce-to-47-days" title="200 days from March 15, 2026, 100 days from March 15, 2027, and 47 days from March 15, 2029" target="_blank" rel="noopener noreferrer">200 days from March 15, 2026, 100 days from March 15, 2027, and 47 days from March 15, 2029</a>.</p>
<p>Once certificate lifetimes keep shrinking, the choice gets less theoretical. Performance and architecture still matter. The first operational question is simpler: how much certificate, TLS, reload, and protocol work do you want humans to keep doing?</p>
<p>Manual certificate management is finished as a serious plan. You can renew a 47-day certificate by hand in theory, the same way you can run production backups by dragging files into a folder. The failure mode is obvious, and it will arrive at the worst time.</p>
<p>All version-sensitive claims below were checked on July 2, 2026. HTTP/3 and ACME support are still moving enough that dates matter.</p>
<h2 id="the-short-answer">The short answer<a href="#the-short-answer" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Caddy is the low-ops choice. It gives you automatic HTTPS, sensible TLS defaults, and HTTP/3. For a small team, a product site, a dashboard, or a containerized service, Caddy usually gets you to the right end state fastest.</p>
<p>Nginx is the control choice. It has the highest ceiling for reverse proxying, load balancing, traffic shaping, and careful tuning. Native ACME closes the old certificate gap, but Nginx still expects you to understand the config model. Fair trade, if you want the control.</p>
<p>Apache is the compatibility choice. Pick it for <code>.htaccess</code>, legacy modules, shared-hosting compatibility, or old WordPress and PHP workflows that expect per-directory overrides. If HTTP/3 matters now, Apache is the weak fit here.</p>
<h2 id="architecture-decides-the-memory-curve">Architecture decides the memory curve<a href="#architecture-decides-the-memory-curve" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Apache 2.4 is built around Multi-Processing Modules. The official <a href="https://httpd.apache.org/docs/2.4/mpm.html" title="Apache MPM documentation" target="_blank" rel="noopener noreferrer">Apache MPM documentation</a> explains that Apache can use <code>prefork</code>, <code>worker</code>, or <code>event</code>, with only one MPM loaded at a time. <code>prefork</code> is process based, <code>worker</code> mixes processes and threads, and <code>event</code> is the modern default on most Unix-like systems.</p>
<p>Apache’s flexibility is useful, but it spreads the work around. You are choosing a process model, module set, virtual host structure, override behavior, and usually a PHP execution model.</p>
<p>Nginx uses a master process and worker processes. Its beginner guide says worker processes handle requests and that Nginx uses an <a href="https://nginx.org/en/docs/beginners_guide.html" title="event-based model with OS-dependent mechanisms" target="_blank" rel="noopener noreferrer">event-based model with OS-dependent mechanisms</a> to distribute work efficiently. That keeps connection handling cheap when the server is mostly moving bytes between clients and upstreams.</p>
<p>Caddy 2 is written in Go. The Caddy architecture docs describe it as a <a href="https://caddyserver.com/docs/architecture" title="single static binary with zero external dependencies" target="_blank" rel="noopener noreferrer">single static binary with zero external dependencies</a>, and Caddy’s HTTP stack sits on Go’s concurrency model. Deployment is simple. Concurrency is good. Under extreme reverse-proxy load, Go runtime behavior, garbage collection, and fewer low-level tuning knobs can matter.</p>
<p>For a reverse proxy pushing very high concurrency and strict tail-latency targets, Nginx still has the sharper toolset.</p>
<h2 id="http3-status-in-2026">HTTP/3 status in 2026<a href="#http3-status-in-2026" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>HTTP/3 runs over QUIC and UDP. Enabling it means the server must listen on UDP 443, the firewall must allow it, and the network path must pass QUIC cleanly.</p>
<p>Nginx has HTTP/3 support through <code>ngx_http_v3_module</code>. The current official docs say the module was introduced in <a href="https://nginx.org/en/docs/http/ngx_http_v3_module.html" title="1.25.0 and still describe it as experimental support" target="_blank" rel="noopener noreferrer">1.25.0 and still describe it as experimental support</a>. That label is not a panic button. It is a reason to test your clients, CDN, firewall, kernel, and observability stack before you call the rollout done.</p>
<p>Caddy supports HTTP/3 by default. Its global options documentation lists the default HTTP protocols as <a href="https://caddyserver.com/docs/caddyfile/options" title="h1 h2 h3" target="_blank" rel="noopener noreferrer"><code>h1 h2 h3</code></a>, and automatic HTTPS is part of the normal site-address flow.</p>
<p>Apache is behind here. Apache’s public <a href="https://httpd.apache.org/docs/2.4/mod/" title="2.4 module index" target="_blank" rel="noopener noreferrer">2.4 module index</a> lists <code>mod_http2</code> for HTTP/2 and <code>mod_proxy_http2</code> for proxying HTTP/2, but no HTTP/3 module. The <code>mod_http2</code> page describes <a href="https://httpd.apache.org/docs/2.4/mod/mod_http2.html" title="support for the HTTP/2 transport layer" target="_blank" rel="noopener noreferrer">support for the HTTP/2 transport layer</a>. As of July 2, 2026, Apache is a poor choice if HTTP/3 is a near-term requirement.</p>
<h2 id="certificate-automation-is-the-main-event">Certificate automation is the main event<a href="#certificate-automation-is-the-main-event" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The certificate lifetime schedule turns ACME from a nice-to-have into infrastructure. If renewals are boring and visible, 47-day certificates are manageable. If renewals depend on a wiki page and a tired person on a Friday, the system is already broken.</p>
<p>Caddy wins this section by design. Its automatic HTTPS docs say Caddy serves public DNS names over HTTPS using certificates from public ACME CAs such as Let’s Encrypt or ZeroSSL, keeps managed certificates renewed, and redirects HTTP to HTTPS automatically. If Caddy knows the public site name, <a href="https://caddyserver.com/docs/automatic-https" title="it serves the site over HTTPS automatically" target="_blank" rel="noopener noreferrer">it serves the site over HTTPS automatically</a>. Issuance, renewal, redirects, OCSP behavior, and protocol defaults are part of the normal path.</p>
<p>Nginx caught up in 2025. It <a href="https://blog.nginx.org/blog/native-support-for-acme-protocol" title="announced a preview release of ngx_http_acme_module" target="_blank" rel="noopener noreferrer">announced a preview release of <code>ngx_http_acme_module</code></a> on August 12, 2025. The announcement says the module provides directives for requesting, installing, and renewing certificates from Nginx configuration, and that it is a Rust-based dynamic module for both Nginx Open Source and NGINX One customers using NGINX Plus. The current module docs say <code>ngx_http_acme_module</code> implements <a href="https://nginx.org/en/docs/http/ngx_http_acme_module.html" title="ACMEv2" target="_blank" rel="noopener noreferrer">ACMEv2</a>, its source is on <a href="https://github.com/nginx/nginx-acme" title="GitHub" target="_blank" rel="noopener noreferrer">GitHub</a>, and a prebuilt <code>nginx-module-acme</code> package exists since 1.29.0. N.WTF’s Debian and Ubuntu builds include the official module by default; its <a href="https://n.wtf/changelog/" title="changelog records nginx-acme being added on November 29, 2025" target="_blank" rel="noopener noreferrer">changelog records <code>nginx-acme</code> being added on November 29, 2025</a>. Let’s Encrypt also <a href="https://letsencrypt.org/2025/09/11/native-acme-for-nginx" title="covered the official module" target="_blank" rel="noopener noreferrer">covered the official module</a>.</p>
<p>A practical Nginx ACME baseline starts with a persistent state directory. The module stores account data, certificates, and private keys there, so create it before reload and keep its permissions tight:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> mkdir</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> /var/cache/nginx/letsencrypt</span></span></code></pre>
<p>The Nginx configuration is longer than Caddy’s, but it now keeps ACME, HTTP/2, and HTTP/3 inside Nginx:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="nginx"><code><span class="line"><span style="color:#F97583">resolver </span><span style="color:#E1E4E8">8.8.8.8:53 ipv6=off valid=5s;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">acme_issuer</span><span style="color:#E1E4E8"> letsencrypt {</span></span>
<span class="line"><span style="color:#F97583">    uri</span><span style="color:#E1E4E8">         https://acme-v02.api.letsencrypt.org/directory;</span></span>
<span class="line"><span style="color:#F97583">    contact</span><span style="color:#E1E4E8">     user@example.com;</span></span>
<span class="line"><span style="color:#F97583">    state_path</span><span style="color:#E1E4E8">  /var/cache/nginx/letsencrypt;</span></span>
<span class="line"><span style="color:#E1E4E8">    accept_terms_of_service;</span></span>
<span class="line"><span style="color:#F97583">    ssl_trusted_certificate </span><span style="color:#E1E4E8">/etc/ssl/certs/ca-certificates.crt;</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">acme_shared_zone</span><span style="color:#E1E4E8"> zone=ngx_acme_shared:1M;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">server</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#79B8FF">80</span><span style="color:#79B8FF"> default_server</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#E1E4E8">[::]:80 </span><span style="color:#79B8FF">default_server</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    server_name </span><span style="color:#E1E4E8">_;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    location</span><span style="color:#B392F0"> /.well-known/ </span><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#F97583">        return</span><span style="color:#79B8FF"> 404</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#E1E4E8">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    location</span><span style="color:#B392F0"> / </span><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#F97583">        return</span><span style="color:#79B8FF"> 301</span><span style="color:#E1E4E8"> https://$host$request_uri;</span></span>
<span class="line"><span style="color:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">server</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#79B8FF">443</span><span style="color:#E1E4E8"> ssl </span><span style="color:#79B8FF">default_server</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#E1E4E8">[::]:443 ssl </span><span style="color:#79B8FF">default_server</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    http2 </span><span style="color:#79B8FF">on</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#79B8FF">443</span><span style="color:#E1E4E8"> quic reuseport;</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#E1E4E8">[::]:443 quic reuseport;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    add_header </span><span style="color:#E1E4E8">Alt-Svc </span><span style="color:#9ECBFF">&#39;h3=&quot;:$</span><span style="color:#E1E4E8">server_port</span><span style="color:#9ECBFF">&quot;; ma=86400&#39;</span><span style="color:#E1E4E8"> always;</span></span>
<span class="line"><span style="color:#F97583">    add_header </span><span style="color:#E1E4E8">X-protocol $server_protocol always;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    server_name </span><span style="color:#E1E4E8">example.com;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    root </span><span style="color:#E1E4E8">/var/www/html;</span></span>
<span class="line"><span style="color:#F97583">    index </span><span style="color:#E1E4E8">index.html;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    ssl_protocols </span><span style="color:#E1E4E8">TLSv1.3;</span></span>
<span class="line"><span style="color:#F97583">    ssl_ecdh_curve </span><span style="color:#E1E4E8">X25519:prime256v1:secp384r1;</span></span>
<span class="line"><span style="color:#F97583">    ssl_prefer_server_ciphers </span><span style="color:#79B8FF">off</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    acme_certificate</span><span style="color:#E1E4E8"> letsencrypt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    ssl_certificate </span><span style="color:#E1E4E8">$acme_certificate;</span></span>
<span class="line"><span style="color:#F97583">    ssl_certificate_key </span><span style="color:#E1E4E8">$acme_certificate_key;</span></span>
<span class="line"><span style="color:#F97583">    ssl_certificate_cache</span><span style="color:#E1E4E8"> max=2;</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre>
<p>Keep <code>ssl_verify</code> on for production. The official module has an <code>ssl_verify off</code> switch, but using it disables verification of the ACME server certificate; with the CA bundle above, the safer default is to verify.</p>
<p>The current docs list HTTP-01 and TLS-ALPN-01 as accepted challenge types. DNS-01 is not listed there. If you need wildcard certificates, verify that path before assuming native Nginx ACME covers it.</p>
<p>Apache can do ACME too. <a href="https://httpd.apache.org/docs/2.4/mod/mod_md.html" title="mod_md" target="_blank" rel="noopener noreferrer"><code>mod_md</code></a> manages domains across virtual hosts and provides certificate provisioning via ACME. Its docs include examples with <code>MDomain</code>, ACME CA settings, challenge selection, renewal windows, and status integration.</p>
<p>Apache’s ACME problem is awareness and ceremony, not capability. You have to know <code>mod_md</code> exists, enable it, configure managed domains, understand virtual host interaction, and keep Apache’s TLS posture in order. In a 47-day certificate world, that is more human work than Caddy and a less direct workflow than modern Nginx.</p>
<h2 id="configuration-difficulty-is-the-visible-symptom">Configuration difficulty is the visible symptom<a href="#configuration-difficulty-is-the-visible-symptom" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Installation is routine in 2026. On Debian or Ubuntu, Apache and Nginx are package-manager basics. Caddy usually starts by adding the official repository, then it is also just a package install. The difference shows up in config.</p>
<p>Caddy can reverse proxy a public HTTPS site in three lines:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>example.com {</span></span>
<span class="line"><span>    reverse_proxy 127.0.0.1:3000</span></span>
<span class="line"><span>}</span></span></code></pre>
<p>That gives you HTTPS automation and, by default, HTTP/1.1, HTTP/2, and HTTP/3. Caddy also has a native JSON configuration model and an admin API. The API docs say Caddy is configured through an HTTP administration endpoint, defaults to <code>localhost:2019</code>, and can load new config with zero downtime while rolling back failed loads.</p>
<p>Nginx is manageable, but explicit. Once HTTP/3 is included, the server block is no longer tiny:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="nginx"><code><span class="line"><span style="color:#F97583">server</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#79B8FF">80</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#E1E4E8">[::]:80;</span></span>
<span class="line"><span style="color:#F97583">    server_name </span><span style="color:#E1E4E8">example.com;</span></span>
<span class="line"><span style="color:#F97583">    return</span><span style="color:#79B8FF"> 301</span><span style="color:#E1E4E8"> https://$host$request_uri;</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">server</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#79B8FF">443</span><span style="color:#E1E4E8"> ssl </span><span style="color:#79B8FF">default_server</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#E1E4E8">[::]:443 ssl </span><span style="color:#79B8FF">default_server</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D">    # HTTP/3 over QUIC</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#79B8FF">443</span><span style="color:#E1E4E8"> quic reuseport;</span></span>
<span class="line"><span style="color:#F97583">    listen </span><span style="color:#E1E4E8">[::]:443 quic reuseport;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D">    # HTTP/2</span></span>
<span class="line"><span style="color:#F97583">    http2 </span><span style="color:#79B8FF">on</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    server_name </span><span style="color:#E1E4E8">example.com;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    ssl_certificate </span><span style="color:#E1E4E8">/etc/nginx/ssl/example.com.crt;</span></span>
<span class="line"><span style="color:#F97583">    ssl_certificate_key </span><span style="color:#E1E4E8">/etc/nginx/ssl/example.com.key;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    add_header </span><span style="color:#E1E4E8">Alt-Svc </span><span style="color:#9ECBFF">&#39;h3=&quot;:$</span><span style="color:#E1E4E8">server_port</span><span style="color:#9ECBFF">&quot;; ma=86400&#39;</span><span style="color:#E1E4E8"> always;</span></span>
<span class="line"><span style="color:#F97583">    add_header </span><span style="color:#E1E4E8">X-protocol $server_protocol always;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    location</span><span style="color:#B392F0"> / </span><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#F97583">        proxy_pass </span><span style="color:#E1E4E8">http://127.0.0.1:3000;</span></span>
<span class="line"><span style="color:#F97583">        proxy_set_header </span><span style="color:#E1E4E8">Host $host;</span></span>
<span class="line"><span style="color:#F97583">        proxy_set_header </span><span style="color:#E1E4E8">X-Forwarded-For $proxy_add_x_forwarded_for;</span></span>
<span class="line"><span style="color:#F97583">        proxy_set_header </span><span style="color:#E1E4E8">X-Forwarded-Proto $scheme;</span></span>
<span class="line"><span style="color:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre>
<p>Readable, widely documented, easy to lint. The Nginx bargain is simple: you get a precise reverse proxy, but you own each decision unless a module or platform owns it for you.</p>
<p>Apache has the most moving parts:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="apache"><code><span class="line"><span style="color:#E1E4E8">MDomain example.com</span></span>
<span class="line"><span style="color:#E1E4E8">MDCertificateAgreement accepted</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">&lt;</span><span style="color:#B392F0">VirtualHost</span><span style="color:#9ECBFF"> *:80</span><span style="color:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#F97583">    ServerName</span><span style="color:#E1E4E8"> example.com</span></span>
<span class="line"><span style="color:#F97583">    Redirect</span><span style="color:#B392F0"> permanent</span><span style="color:#9ECBFF"> /</span><span style="color:#9ECBFF"> https://example.com/</span></span>
<span class="line"><span style="color:#E1E4E8">&lt;/</span><span style="color:#B392F0">VirtualHost</span><span style="color:#E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">&lt;</span><span style="color:#B392F0">VirtualHost</span><span style="color:#9ECBFF"> *:443</span><span style="color:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#F97583">    ServerName</span><span style="color:#E1E4E8"> example.com</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    SSLEngine</span><span style="color:#B392F0"> on</span></span>
<span class="line"><span style="color:#E1E4E8">    Protocols h2 http/</span><span style="color:#79B8FF">1</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">1</span><span style="color:#E1E4E8"> acme-tls/</span><span style="color:#79B8FF">1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    ProxyPreserveHost</span><span style="color:#B392F0"> On</span></span>
<span class="line"><span style="color:#F97583">    ProxyPass</span><span style="color:#E1E4E8"> / http://</span><span style="color:#79B8FF">127</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">1</span><span style="color:#E1E4E8">:</span><span style="color:#79B8FF">3000</span><span style="color:#E1E4E8">/</span></span>
<span class="line"><span style="color:#F97583">    ProxyPassReverse</span><span style="color:#E1E4E8"> / http://</span><span style="color:#79B8FF">127</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">.</span><span style="color:#79B8FF">1</span><span style="color:#E1E4E8">:</span><span style="color:#79B8FF">3000</span><span style="color:#E1E4E8">/</span></span>
<span class="line"><span style="color:#E1E4E8">&lt;/</span><span style="color:#B392F0">VirtualHost</span><span style="color:#E1E4E8">&gt;</span></span></code></pre>
<p>Apache’s power is real, but the surface area is larger. <code>httpd.conf</code>, virtual host inheritance, MPM choice, <code>.htaccess</code>, <code>mod_ssl</code>, <code>mod_proxy</code>, <code>mod_md</code>, and per-directory behavior all become part of the job.</p>
<h2 id="performance-without-fake-benchmark-theater">Performance, without fake benchmark theater<a href="#performance-without-fake-benchmark-theater" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Nginx is still the ceiling for high-concurrency reverse proxying. Its event-driven model, mature upstream handling, low memory footprint, and tuning surface are why it remains common at the edge.</p>
<p>Old comparison posts often underrate Caddy. Static file serving and ordinary reverse proxy workloads are fine. For most product sites, APIs, admin panels, and internal tools, app latency and database latency will dominate the difference.</p>
<p>The Caddy caveat lives at the far end: very high concurrency, strict memory budgets, and tail latency under sustained proxy load. Go’s runtime and garbage collector are part of the operating model. Nginx gives you more control when that level of tuning matters.</p>
<p>Apache can perform well with the event MPM, but legacy shape still matters. The prefork model remains common in older PHP stacks and shared-hosting environments, and prefork is expensive per connection. <code>.htaccess</code> can also force per-directory checks at request time. Useful, but not free.</p>
<p>Market share should inform your risk model, not decide the winner. W3Techs’ web server survey in late June 2026 showed <a href="https://w3techs.com/technologies/overview/web_server" title="Nginx at 31.8%, Apache at 23.2%, and Caddy at 0.2%" target="_blank" rel="noopener noreferrer">Nginx at 31.8%, Apache at 23.2%, and Caddy at 0.2%</a> of websites whose web server W3Techs knows. Nginx and Apache have deeper operational folklore. Caddy has less market share, but its defaults remove work that older stacks still hand to the operator.</p>
<h2 id="apaches-real-moat-is-htaccess">Apache’s real moat is <code>.htaccess</code><a href="#apaches-real-moat-is-htaccess" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Apache still owns one use case the others do not replace cleanly: <code>.htaccess</code>.</p>
<p>For shared hosting, that matters. A provider can let customers change rewrite rules, authentication, redirects, cache headers, PHP behavior, and per-directory settings without main server config access. WordPress, legacy PHP, and control-panel hosting grew around that model.</p>
<p>The same mechanism has a cost. <code>.htaccess</code> moves configuration out of one central reviewable file and into the document tree. Apache may need to check directories for override files on requests.</p>
<p>If you run a modern VPS, container, or single-tenant app server, <code>.htaccess</code> is usually a liability. If you run a shared host or a legacy app that expects it, it may be the whole reason Apache is still the right answer.</p>
<h2 id="nginx-has-a-community-split-to-watch">Nginx has a community split to watch<a href="#nginx-has-a-community-split-to-watch" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Nginx is still a strong default. Its ecosystem is less unified than it used to be.</p>
<p>F5 acquired NGINX in 2019, and the boundary between open source Nginx, NGINX Plus, and NGINX One remains a recurring operator discussion. In February 2024, Maxim Dounin started freenginx, whose site describes it as an effort to preserve free and open Nginx development. Angie is another Nginx-family project; its own site says the open source Angie server was created as a fork of Nginx. In 2026, “Nginx” might mean open source Nginx, NGINX Plus, freenginx, Angie, OpenResty, <a href="https://n.wtf/" title="N.WTF" target="_blank" rel="noopener noreferrer">N.WTF</a> packages, or a vendor platform built around Nginx semantics.</p>
<h2 id="other-servers-worth-knowing">Other servers worth knowing<a href="#other-servers-worth-knowing" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>LiteSpeed and OpenLiteSpeed deserve a look for WordPress-heavy deployments, especially where LSCache is central. HAProxy is excellent when the job is load balancing, TLS termination, traffic routing, health checks, and proxy behavior. Traefik fits container-native routing well when your world is Docker labels, Kubernetes ingress, service discovery, and automatic Let’s Encrypt for many short-lived services. They are narrower picks than Apache, Nginx, and Caddy for a general-purpose VPS web server.</p>
<h2 id="decision-guide">Decision guide<a href="#decision-guide" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Choose Caddy when:</p>
<ul>
<li>you want HTTPS and HTTP/3 as defaults</li>
<li>your team is small and ops time is scarce</li>
<li>you deploy services frequently and like API-driven reloads</li>
<li>you value simple config over maximum tuning depth</li>
</ul>
<p>Choose Nginx when:</p>
<ul>
<li>you run high-traffic reverse proxy workloads</li>
<li>you need precise upstream, caching, buffering, or rate-limit behavior</li>
<li>your team already knows Nginx well</li>
<li>you want native ACME but still prefer explicit server configuration</li>
</ul>
<p>Choose Apache when:</p>
<ul>
<li><code>.htaccess</code> support is required</li>
<li>you are operating a shared-hosting or legacy PHP environment</li>
<li>the application depends on Apache modules or old deployment assumptions</li>
<li>HTTP/3 can wait</li>
</ul>
<p>For a new 2026 VPS deployment, my default is Caddy for simple apps, Nginx for serious proxy and tuning work, and Apache when Apache compatibility is part of the requirement.</p>





































































































<table><thead><tr><th>Dimension</th><th>Apache 2.4</th><th>Nginx</th><th>Caddy 2</th></tr></thead><tbody><tr><td>First release / language</td><td>1995 / C</td><td>2004 / C</td><td>2015 / Go</td></tr><tr><td>Architecture</td><td>MPM process/thread model</td><td>Event-driven workers</td><td>Go runtime and goroutines</td></tr><tr><td>HTTP/3</td><td>No public Apache 2.4 module</td><td>Yes, official module docs still say experimental</td><td>Yes, default protocol set includes <code>h3</code></td></tr><tr><td>ACME automation</td><td><code>mod_md</code>, capable but manual</td><td><code>ngx_http_acme_module</code>, native ACMEv2</td><td>Native automatic HTTPS</td></tr><tr><td>TLS defaults</td><td>Operator-managed</td><td>Operator-managed</td><td>Secure by default for common sites</td></tr><tr><td>Installation</td><td>Easy package install</td><td>Easy package install</td><td>Easy after adding official repo</td></tr><tr><td>Configuration difficulty</td><td>Highest</td><td>Medium</td><td>Lowest</td></tr><tr><td>Config and reload</td><td><code>httpd.conf</code>, vhosts, <code>.htaccess</code>, reload</td><td><code>nginx.conf</code>, graceful reload</td><td>Caddyfile or JSON API, zero-downtime reload</td></tr><tr><td>High-concurrency proxying</td><td>Acceptable with event MPM, weak in legacy prefork stacks</td><td>Best fit</td><td>Good for most sites</td></tr><tr><td>Memory profile</td><td>Can be high</td><td>Very low</td><td>Moderate</td></tr><tr><td>Reverse proxy / load balancing</td><td>Capable, less common as the edge default</td><td>Excellent</td><td>Good</td></tr><tr><td><code>.htaccess</code></td><td>Yes</td><td>No</td><td>No</td></tr><tr><td>Learning curve</td><td>Steep</td><td>Moderate</td><td>Gentle</td></tr><tr><td>W3Techs share, late June 2026</td><td>23.2%</td><td>31.8%</td><td>0.2%</td></tr><tr><td>Best fit</td><td>Legacy apps, shared hosting, Apache module stacks</td><td>High-traffic reverse proxy and tuned edge services</td><td>Small teams, fast launches, container and VPS apps</td></tr></tbody></table>
<h2 id="vps-control-matters-for-http3">VPS control matters for HTTP/3<a href="#vps-control-matters-for-http3" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>HTTP/3 needs UDP 443. Certificate automation needs reliable inbound validation or correct DNS automation. Serious web-server tuning needs root access, firewall control, kernel and sysctl visibility, logs, and a network where you can test the actual path.</p>
<p>A VPS is cleaner than shared hosting for this. On Riven Cloud, every plan is an unmanaged KVM VPS with full root access, a dedicated IPv4 address, a <code>/64</code> IPv6 block, NVMe SSD storage, daily backups, and a 1 Gbps network port. If you are choosing a web server for users in mainland China, test the route from <a href="https://sa.net/network/" title="Tokyo or Singapore">Tokyo or Singapore</a> first, then compare plans on the <a href="https://sa.net/pricing/" title="pricing page">pricing page</a>.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The 2026 web server choice starts with automation. Caddy gives you the shortest path to a correct modern HTTPS setup. Nginx gives you the highest ceiling when traffic shape and proxy control matter. Apache remains the compatibility king for <code>.htaccess</code>, shared hosting, and old module ecosystems, but HTTP/3 absence and heavier configuration make it harder to justify for new deployments.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="Nginx" term="Nginx"/>
        <category label="Apache" term="Apache"/>
        <category label="Caddy" term="Caddy"/>
        <category label="Web Server" term="Web Server"/>
        <category label="HTTP/3" term="HTTP/3"/>
        <category label="ACME" term="ACME"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How to secure SSH on a VPS without locking yourself out]]></title>
        <id>https://sa.net/blog/secure-ssh-on-a-vps/</id>
        <link href="https://sa.net/blog/secure-ssh-on-a-vps/"/>
        <updated>2026-07-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A practical SSH hardening guide for Linux VPS operators: add keys first, disable password login, move the port safely, configure fail2ban, and tighten the firewall.]]></summary>
        <content type="html"><![CDATA[<p>SSH is usually the first service that internet scanners touch. Put a fresh VPS online with password login enabled on port 22, and the authentication log will often start collecting junk within hours.</p>
<p>The fix is mostly order. Add and test an SSH key first. Then disable password login, move the listener only after the new port is open, configure fail2ban, and close whatever you no longer need. Key-only SSH does the serious work. A custom port makes the logs quieter. fail2ban blocks noisy clients, but it does not make weak authentication safe.</p>
<p>Use one rule for the whole job: build the new entrance before closing the old one. Do not disable a login method, restart SSH, or remove a firewall rule until the replacement path works from a new terminal.</p>
<p>This is written for people running an unmanaged Linux VPS. If you are still deciding whether root access is worth the operational work, read <a href="https://sa.net/blog/vps-vs-shared-hosting/" title="VPS vs shared hosting">VPS vs shared hosting</a> first.</p>
<h2 id="before-you-start-dont-lock-yourself-out">Before you start: don’t lock yourself out<a href="#before-you-start-dont-lock-yourself-out" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Keep one working SSH session open the whole time. Do not close it just because the last command succeeded. SSH restarts usually leave existing sessions alone, and that terminal is your way back in if the next login test fails.</p>
<p>Run the OpenSSH server config test before every restart:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> sshd</span><span style="color:#79B8FF"> -t</span></span></code></pre>
<p>The <code>-t</code> flag makes <code>sshd</code> check the configuration and keys, then exit without starting a new daemon, as documented in the <a href="https://man.openbsd.org/sshd" title="OpenSSH sshd manual" target="_blank" rel="noopener noreferrer">OpenSSH sshd manual</a>. If it prints an error, fix that first.</p>
<p>After each change, open a second terminal and log in again. Move on only after the new session works.</p>
<p>The service name depends on the distro:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D"># Debian and Ubuntu</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> ssh</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># AlmaLinux, Rocky Linux, and CentOS Stream</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> sshd</span></span></code></pre>
<h2 id="step-1-generate-an-ssh-key-and-add-it-first">Step 1: generate an SSH key and add it first<a href="#step-1-generate-an-ssh-key-and-add-it-first" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Start with the key because every later step depends on key login already working. OpenSSH supports several key types through <code>ssh-keygen</code>; for a normal modern server, Ed25519 is a sensible default. Use RSA 4096 only when an older server or client cannot use Ed25519. The <a href="https://man.openbsd.org/ssh-keygen" title="ssh-keygen manual" target="_blank" rel="noopener noreferrer">ssh-keygen manual</a> documents both key types.</p>
<p>On macOS or Linux:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-keygen</span><span style="color:#79B8FF"> -t</span><span style="color:#9ECBFF"> ed25519</span><span style="color:#79B8FF"> -C</span><span style="color:#9ECBFF"> &quot;you@host&quot;</span></span></code></pre>
<p>The private key is usually saved as <code>~/.ssh/id_ed25519</code>. The public key is <code>~/.ssh/id_ed25519.pub</code>.</p>
<p>On Windows, use the built-in OpenSSH client from PowerShell:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="powershell"><code><span class="line"><span style="color:#E1E4E8">ssh</span><span style="color:#F97583">-</span><span style="color:#E1E4E8">keygen </span><span style="color:#F97583">-</span><span style="color:#E1E4E8">t ed25519 </span><span style="color:#F97583">-</span><span style="color:#E1E4E8">C </span><span style="color:#9ECBFF">&quot;you@host&quot;</span></span></code></pre>
<p>PuTTY users can generate the key with PuTTYgen, then export the public key in OpenSSH format. If you log in with PuTTY, keep the private key in PuTTY’s format. If you log in from Terminal, PowerShell, or WSL, keep the private key in OpenSSH format.</p>
<p>Set a passphrase when <code>ssh-keygen</code> asks. It protects the private key if your laptop is stolen or a backup leaks. <code>ssh-agent</code> keeps the key usable without making you type the passphrase for every login:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#79B8FF">eval</span><span style="color:#9ECBFF"> &quot;$(</span><span style="color:#B392F0">ssh-agent</span><span style="color:#79B8FF"> -s</span><span style="color:#9ECBFF">)&quot;</span></span>
<span class="line"><span style="color:#B392F0">ssh-add</span><span style="color:#9ECBFF"> ~/.ssh/id_ed25519</span></span></code></pre>
<p>On Windows PowerShell:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="powershell"><code><span class="line"><span style="color:#79B8FF">Start-Service</span><span style="color:#E1E4E8"> ssh</span><span style="color:#F97583">-</span><span style="color:#E1E4E8">agent</span></span>
<span class="line"><span style="color:#E1E4E8">ssh</span><span style="color:#F97583">-</span><span style="color:#E1E4E8">add $</span><span style="color:#79B8FF">env:</span><span style="color:#E1E4E8">USERPROFILE\.ssh\id_ed25519</span></span></code></pre>
<p>For a new Riven Cloud server, add the key before you install the OS.</p>
<p>Option 1: generate the key locally. In the Riven Cloud control panel, go to SSH keys, click Add Key, paste the contents of your <code>.pub</code> file, give it a clear name, and select it during OS install or reinstall.</p>
<p>Option 2: generate the key in the control panel. Go to <code>SSH key</code> &gt; <code>Add Key</code> &gt; <code>Generate Key Pair</code>, download the private key, and store it somewhere safe. Choose OpenSSH format for Terminal or PowerShell, or PuTTY format for PuTTY on Windows. Select that key when you install the server.</p>
<p>For an already-running server where password login still works, push the public key with <code>ssh-copy-id</code>:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-copy-id</span><span style="color:#79B8FF"> -i</span><span style="color:#9ECBFF"> ~/.ssh/id_ed25519.pub</span><span style="color:#9ECBFF"> root@SERVER_IP</span></span></code></pre>
<p>Test the key from a new terminal:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#79B8FF"> -i</span><span style="color:#9ECBFF"> ~/.ssh/id_ed25519</span><span style="color:#9ECBFF"> root@SERVER_IP</span></span></code></pre>
<p>That login must work before you continue. If it fails, stop here and check the key path, username, public key, file permissions, or control panel selection. Leave password login alone until key login works.</p>
<h2 id="step-2-disable-password-login-and-lock-down-root">Step 2: disable password login and lock down root<a href="#step-2-disable-password-login-and-lock-down-root" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Password login is what turns random SSH scans into a guessing attack. Once key login works, disable password authentication and keyboard-interactive authentication. For this pass, keep root key login available with <code>PermitRootLogin prohibit-password</code>: root cannot use a password, but a valid key still works. The options are documented in <a href="https://man.openbsd.org/sshd_config" title="sshd_config(5)" target="_blank" rel="noopener noreferrer">sshd_config(5)</a>.</p>
<p>Create a drop-in file:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> install</span><span style="color:#79B8FF"> -d</span><span style="color:#79B8FF"> -m</span><span style="color:#79B8FF"> 755</span><span style="color:#9ECBFF"> /etc/ssh/sshd_config.d</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> tee</span><span style="color:#9ECBFF"> /etc/ssh/sshd_config.d/10-hardening.conf</span><span style="color:#F97583"> &gt;</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#F97583"> &lt;&lt;</span><span style="color:#9ECBFF">&#39;EOF&#39;</span></span>
<span class="line"><span style="color:#9ECBFF">PubkeyAuthentication yes</span></span>
<span class="line"><span style="color:#9ECBFF">PasswordAuthentication no</span></span>
<span class="line"><span style="color:#9ECBFF">KbdInteractiveAuthentication no</span></span>
<span class="line"><span style="color:#9ECBFF">PermitRootLogin prohibit-password</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>Most current Debian, Ubuntu, AlmaLinux, Rocky Linux, and CentOS Stream images include <code>/etc/ssh/sshd_config.d/*.conf</code> from the main <code>sshd_config</code>. If your image is unusual, check the main file for this line:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>Include /etc/ssh/sshd_config.d/*.conf</span></span></code></pre>
<p>Validate first:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> sshd</span><span style="color:#79B8FF"> -t</span></span></code></pre>
<p>Restart SSH:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D"># Debian and Ubuntu</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> ssh</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># AlmaLinux, Rocky Linux, and CentOS Stream</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> sshd</span></span></code></pre>
<p>Open a new terminal and test key login again:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#79B8FF"> -i</span><span style="color:#9ECBFF"> ~/.ssh/id_ed25519</span><span style="color:#9ECBFF"> root@SERVER_IP</span></span></code></pre>
<p>Then confirm password-only login is refused from a new terminal:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> PubkeyAuthentication=no</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> IdentitiesOnly=yes</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> PreferredAuthentications=keyboard-interactive,password</span><span style="color:#9ECBFF"> root@SERVER_IP</span></span></code></pre>
<p>The server should reject the attempt without showing a password prompt. If key login still works and that password-only attempt fails, the biggest SSH hardening win is already done.</p>
<p>A non-root sudo user plus <code>PermitRootLogin no</code> is a stronger long-term setup, but do it only after that user has been tested. This guide keeps it optional because this is where people lock themselves out. If you make that change, create the sudo user, add its key, test <code>sudo</code>, then disable root login.</p>
<h2 id="step-3-change-the-ssh-port-for-noise-reduction">Step 3: change the SSH port for noise reduction<a href="#step-3-change-the-ssh-port-for-noise-reduction" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Moving SSH away from port 22 is housekeeping. It does not make SSH stronger, and it will not save a server that still accepts weak passwords. It mainly cuts down hits from scanners that only try the default port. Do it after key-only login works, and treat it as log cleanup.</p>
<p>This example uses port <code>2222</code>. If you choose another port, use the same value in SSH, the firewall, and fail2ban.</p>
<p>Open the new port in the firewall before you restart SSH.</p>
<p>On AlmaLinux, Rocky Linux, and CentOS Stream, <code>firewalld</code> is commonly enabled on VPS templates and new inbound ports are closed by default. Add <code>2222/tcp</code> first:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --permanent</span><span style="color:#79B8FF"> --add-port=2222/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --reload</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --list-ports</span></span></code></pre>
<p>The <code>firewall-cmd</code> syntax is documented in the <a href="https://firewalld.org/documentation/man-pages/firewall-cmd.html" title="firewalld command manual" target="_blank" rel="noopener noreferrer">firewalld command manual</a>.</p>
<p>On Ubuntu or Debian, UFW may or may not be enabled. Check before you add rules:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> status</span></span></code></pre>
<p>If UFW is active, allow the new port:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 2222/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> status</span></span></code></pre>
<p>The <a href="https://manpages.ubuntu.com/manpages/noble/man8/ufw.8.html" title="Ubuntu ufw manual" target="_blank" rel="noopener noreferrer">Ubuntu ufw manual</a> documents <code>allow</code>, <code>delete</code>, and status commands.</p>
<p>Now change the SSH listener. On most servers, use a temporary dual-port drop-in so port 22 stays available while you test port 2222:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> tee</span><span style="color:#9ECBFF"> /etc/ssh/sshd_config.d/20-port.conf</span><span style="color:#F97583"> &gt;</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#F97583"> &lt;&lt;</span><span style="color:#9ECBFF">&#39;EOF&#39;</span></span>
<span class="line"><span style="color:#9ECBFF">Port 22</span></span>
<span class="line"><span style="color:#9ECBFF">Port 2222</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>Validate and restart:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> sshd</span><span style="color:#79B8FF"> -t</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># Debian and Ubuntu</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> ssh</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># AlmaLinux, Rocky Linux, and CentOS Stream</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> sshd</span></span></code></pre>
<p>Open a new terminal and test the new port:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#79B8FF"> -p</span><span style="color:#79B8FF"> 2222</span><span style="color:#79B8FF"> -i</span><span style="color:#9ECBFF"> ~/.ssh/id_ed25519</span><span style="color:#9ECBFF"> root@SERVER_IP</span></span></code></pre>
<p>Remove port 22 from the SSH listener only after port 2222 works:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> tee</span><span style="color:#9ECBFF"> /etc/ssh/sshd_config.d/20-port.conf</span><span style="color:#F97583"> &gt;</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#F97583"> &lt;&lt;</span><span style="color:#9ECBFF">&#39;EOF&#39;</span></span>
<span class="line"><span style="color:#9ECBFF">Port 2222</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> sshd</span><span style="color:#79B8FF"> -t</span></span></code></pre>
<p>Restart SSH again with the correct service name for your distro. Then open one more new session on port 2222.</p>
<h3 id="ubuntu-and-debian-check-sshsocket">Ubuntu and Debian: check ssh.socket<a href="#ubuntu-and-debian-check-sshsocket" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>Some Debian or Ubuntu systems use <code>ssh.socket</code>. When socket activation is active, systemd owns the listening socket, so the <code>Port</code> line in <code>sshd_config</code> may not control the initial listener. Check it:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> ssh.socket</span></span></code></pre>
<p>If it is active and listening, override the socket instead of relying only on <code>20-port.conf</code>:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> edit</span><span style="color:#9ECBFF"> ssh.socket</span></span></code></pre>
<p>Use both ports for the first test:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="ini"><code><span class="line"><span style="color:#B392F0">[Socket]</span></span>
<span class="line"><span style="color:#F97583">ListenStream</span><span style="color:#E1E4E8">=</span></span>
<span class="line"><span style="color:#F97583">ListenStream</span><span style="color:#E1E4E8">=22</span></span>
<span class="line"><span style="color:#F97583">ListenStream</span><span style="color:#E1E4E8">=2222</span></span></code></pre>
<p>Then validate SSH config, reload systemd, and restart the socket:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> sshd</span><span style="color:#79B8FF"> -t</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> daemon-reload</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> ssh.socket</span></span></code></pre>
<p>After <code>ssh -p 2222 root@SERVER_IP</code> works from a new terminal, edit the socket again and leave only this listener:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="ini"><code><span class="line"><span style="color:#B392F0">[Socket]</span></span>
<span class="line"><span style="color:#F97583">ListenStream</span><span style="color:#E1E4E8">=</span></span>
<span class="line"><span style="color:#F97583">ListenStream</span><span style="color:#E1E4E8">=2222</span></span></code></pre>
<p>The <code>ListenStream</code> behavior comes from the <a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html" title="systemd.socket documentation" target="_blank" rel="noopener noreferrer">systemd.socket documentation</a>. Keep the order boring: add the new listener, test it, then remove the old listener.</p>
<h3 id="selinux-note">SELinux note<a href="#selinux-note" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p>Riven Cloud default Linux templates ship with SELinux disabled, so those templates do not need an SELinux port change.</p>
<p>If you enabled SELinux yourself on a RHEL-family server, allow the new SSH port before restart:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> dnf</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> policycoreutils-python-utils</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> semanage</span><span style="color:#9ECBFF"> port</span><span style="color:#79B8FF"> -a</span><span style="color:#79B8FF"> -t</span><span style="color:#9ECBFF"> ssh_port_t</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> tcp</span><span style="color:#79B8FF"> 2222</span></span></code></pre>
<p>The <code>semanage port</code> command is documented in the <a href="https://man7.org/linux/man-pages/man8/semanage-port.8.html" title="semanage-port manual" target="_blank" rel="noopener noreferrer">semanage-port manual</a>. Do not run it unless SELinux is actually enabled.</p>
<p>Once you can log in on port 2222, remove port 22 from the firewall.</p>
<p>For firewalld, the default SSH opening is usually the <code>ssh</code> service, not a raw port rule:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --permanent</span><span style="color:#79B8FF"> --remove-service=ssh</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --permanent</span><span style="color:#79B8FF"> --remove-port=22/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --reload</span></span></code></pre>
<p>For UFW:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> delete</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 22/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> delete</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> OpenSSH</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> status</span></span></code></pre>
<p>Run the delete command that matches what your firewall actually shows. Never remove port 22 before a new session on port 2222 works.</p>
<h2 id="step-4-stop-brute-force-with-fail2ban">Step 4: stop brute force with fail2ban<a href="#step-4-stop-brute-force-with-fail2ban" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>fail2ban is useful after SSH authentication is already sane. Riven Cloud’s default Linux templates ship with fail2ban preinstalled. Verify it anyway:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> fail2ban-client</span><span style="color:#79B8FF"> --version</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> fail2ban-client</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> sshd</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> fail2ban</span></span></code></pre>
<p>If it is missing on a custom image, install it:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D"># Debian and Ubuntu</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> apt</span><span style="color:#9ECBFF"> update</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> apt</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> fail2ban</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># AlmaLinux, Rocky Linux, and CentOS Stream</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> dnf</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> epel-release</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> dnf</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> fail2ban</span></span></code></pre>
<p>Put local overrides under <code>/etc/fail2ban/jail.d/</code>. Do not edit <code>jail.conf</code> directly; fail2ban’s upstream configuration is meant to be overridden locally, as shown by its <a href="https://github.com/fail2ban/fail2ban/blob/master/config/jail.conf" title="default jail configuration" target="_blank" rel="noopener noreferrer">default jail configuration</a>.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> tee</span><span style="color:#9ECBFF"> /etc/fail2ban/jail.d/ssh.conf</span><span style="color:#F97583"> &gt;</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#F97583"> &lt;&lt;</span><span style="color:#9ECBFF">&#39;EOF&#39;</span></span>
<span class="line"><span style="color:#9ECBFF">[sshd]</span></span>
<span class="line"><span style="color:#9ECBFF">enabled = true</span></span>
<span class="line"><span style="color:#9ECBFF">port = 2222</span></span>
<span class="line"><span style="color:#9ECBFF">backend = systemd</span></span>
<span class="line"><span style="color:#9ECBFF">maxretry = 5</span></span>
<span class="line"><span style="color:#9ECBFF">findtime = 10m</span></span>
<span class="line"><span style="color:#9ECBFF">bantime = 1h</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>The <code>port</code> value must match the port from Step 3. If fail2ban watches port 22 while SSH listens on 2222, the jail is watching the wrong place.</p>
<p>Modern Debian, Ubuntu, AlmaLinux, Rocky Linux, and CentOS Stream systems normally log SSH authentication through the systemd journal, so <code>backend = systemd</code> is a good default. If your image writes only to traditional log files, use a log file backend instead.</p>
<p>Enable and start fail2ban:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> enable</span><span style="color:#79B8FF"> --now</span><span style="color:#9ECBFF"> fail2ban</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> fail2ban-client</span><span style="color:#9ECBFF"> status</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> fail2ban-client</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> sshd</span></span></code></pre>
<p>The <code>sshd</code> status output shows the jail, current failures, and banned IP addresses. With key-only auth in place, brute force attempts cannot log in by guessing a password. fail2ban still helps by blocking noisy scanners and keeping abusive clients from hitting your logs all day.</p>
<h2 id="step-5-tighten-the-firewall-and-extra-ssh-knobs">Step 5: tighten the firewall and extra SSH knobs<a href="#step-5-tighten-the-firewall-and-extra-ssh-knobs" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>After SSH is stable on the new port, keep the firewall plain. Deny inbound traffic by default, then open only what the server actually serves.</p>
<p>For a web server, that often means SSH plus HTTP and HTTPS:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D"># firewalld</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --permanent</span><span style="color:#79B8FF"> --add-service=http</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --permanent</span><span style="color:#79B8FF"> --add-service=https</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --reload</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> firewall-cmd</span><span style="color:#79B8FF"> --list-all</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># UFW</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> default</span><span style="color:#9ECBFF"> deny</span><span style="color:#9ECBFF"> incoming</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> default</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> outgoing</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 2222/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 80/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> allow</span><span style="color:#9ECBFF"> 443/tcp</span></span>
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ufw</span><span style="color:#9ECBFF"> status</span></span></code></pre>
<p>RHEL-family VPS templates are a useful model here: with firewalld enabled, SSH is allowed and random ports are closed. Keep that habit. Add a port when a service needs it, and remove the port when the service is gone.</p>
<p>Do not mix SSH cleanup with unrelated performance work. If a site feels slow after hardening, diagnose that separately with a page-load and server check such as <a href="https://sa.net/blog/why-is-my-website-slow/" title="why is my website slow">why is my website slow</a>.</p>
<p>A few optional SSH settings can make abuse less noisy:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>MaxAuthTries 3</span></span>
<span class="line"><span>LoginGraceTime 30</span></span>
<span class="line"><span>AllowUsers deploy admin</span></span>
<span class="line"><span># or:</span></span>
<span class="line"><span># AllowGroups ssh-users</span></span></code></pre>
<p>Use <code>AllowUsers</code> or <code>AllowGroups</code> only after the named user or group has been tested in a new session. The same rule still applies: test the new path before closing the old one.</p>
<h2 id="what-actually-protects-you-when-you-secure-ssh-on-a-vps">What actually protects you when you secure SSH on a VPS<a href="#what-actually-protects-you-when-you-secure-ssh-on-a-vps" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Do not treat every control as equal. They are not doing the same job.</p>
<ol>
<li>Key-only authentication with password login disabled removes password guessing from the attack path.</li>
<li>A minimal firewall and a non-root sudo user reduce exposure and limit blast radius.</li>
<li>fail2ban cuts log noise and blocks abusive scanners.</li>
<li>Changing the SSH port reduces noise, not risk by itself.</li>
</ol>
<p>Treat the port change as cleanup, not the main defense. A server on port 2222 with password login enabled is still a weak SSH server. A server on port 22 with passwords disabled and strong keys is already much harder to brute force.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The safe order is simple: add and test the key, disable passwords, open and test the new port, configure fail2ban, then remove anything you no longer need.</p>
<p>Riven Cloud’s Linux templates ship with fail2ban preinstalled, and the control panel can add SSH keys during deployment. If you need an unmanaged KVM VPS with root access, daily backups, and Tokyo or Singapore locations, you can <a href="https://sa.net/pricing/" title="view VPS plans">view VPS plans</a>.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="Security" term="Security"/>
        <category label="VPS" term="VPS"/>
        <category label="SSH" term="SSH"/>
        <category label="Infrastructure" term="Infrastructure"/>
        <category label="Linux" term="Linux"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[VPS vs Shared Hosting: Which Do You Need?]]></title>
        <id>https://sa.net/blog/vps-vs-shared-hosting/</id>
        <link href="https://sa.net/blog/vps-vs-shared-hosting/"/>
        <updated>2026-06-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A practical comparison of VPS and shared hosting for site owners choosing between convenience, control, cost, and operations work.]]></summary>
        <content type="html"><![CDATA[<p>VPS vs shared hosting is usually framed as a ladder: start cheap, then move up when you outgrow it. That is partly true, but it misses the more useful tension.</p>
<p>The real tradeoff is control versus convenience.</p>
<p>Shared hosting gives you a prepared environment. You upload a site, click around a control panel, and let the provider handle most of the server work. A VPS gives you a server-like environment with root access. You decide what runs, how it is configured, and how it is maintained.</p>
<p>Neither model is automatically better. A portfolio site, small WordPress site, or local business page may be happier on shared hosting for years. A custom app, API, bot, database-backed service, or traffic-heavy site may become awkward on shared hosting quickly. The difference between VPS and shared hosting is less about status and more about your stage, skill level, and tolerance for operations work.</p>
<h2 id="what-shared-hosting-and-vps-actually-are">What shared hosting and VPS actually are<a href="#what-shared-hosting-and-vps-actually-are" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The simplest analogy is housing.</p>
<p>Shared hosting is like renting a room in a shared apartment. The kitchen, utilities, locks, and building rules are handled for you. You get a small private area, but the building owner decides what appliances are allowed, how noisy the neighbors can be, and what you can change.</p>
<p>A VPS is closer to having your own small house. The land still belongs to a larger provider, but your environment is isolated. You decide what to install, how to wire the rooms, and when to renovate. You also deal with the consequences when something leaks at 3am.</p>
<p>Underneath the analogy, shared hosting places many customer sites inside a provider-managed environment. CPU, memory, disk, web server configuration, PHP versions, mail handling, SSL tooling, backups, and control panel behavior are mostly standardized.</p>
<p>A VPS uses virtualization to give you an isolated operating system instance. You usually get a fixed amount of vCPU, RAM, disk, transfer, and network access. The provider owns the physical host and network. You own the software stack inside your virtual server.</p>
<h2 id="shared-hosting-strengths-and-limits">Shared hosting: strengths and limits<a href="#shared-hosting-strengths-and-limits" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Shared hosting is popular because it removes friction.</p>
<p>For a simple site, that matters. You do not need to install a web server, configure PHP-FPM, set up a firewall, harden SSH, schedule backups, or think about unattended security upgrades. The provider gives you a panel, a file manager or SFTP access, database creation tools, DNS helpers, SSL buttons, and often one-click installers.</p>
<p>That model is a good fit for many sites:</p>
<ul>
<li>static HTML/CSS pages</li>
<li>small WordPress sites</li>
<li>basic PHP apps</li>
<li>landing pages</li>
<li>small business sites</li>
<li>hobby projects where uptime is useful but not mission critical</li>
</ul>
<p>The best part is not the low price. It is the low mental load. You can build the site and avoid becoming the server administrator.</p>
<p>The limits are real, though. Many shared hosts do not provide shell access, or they provide a restricted shell that is not useful for serious deployment work. The stack is usually centered on PHP, static files, MySQL or MariaDB, and a provider-approved control panel. If your app needs Node.js workers, Python services, background queues, custom daemons, Docker, Redis, PostgreSQL, or long-running jobs, shared hosting may fight you.</p>
<p>Resource limits can also be opaque. A plan may advertise generous storage or transfer while enforcing CPU seconds, process counts, memory caps, inode limits, database query limits, cron frequency limits, or request throttles elsewhere. Those caps are not always bad. They protect the shared platform. They also mean your site can hit a wall without an obvious upgrade path.</p>
<p>Noisy neighbors are the other classic problem. Since many sites share the same underlying platform, another customer can affect performance if isolation is weak or the node is overloaded. Good shared hosts manage this carefully. Cheap shared hosts sometimes do not.</p>
<p>Shared hosting also tends to create lock-in around the panel and workflow. You may get used to provider-specific backup tools, staging tools, mailboxes, SSL buttons, and file deployment patterns. Moving later can take more work than expected.</p>
<h2 id="vps-strengths-and-limits">VPS: strengths and limits<a href="#vps-strengths-and-limits" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>A VPS gives you control first.</p>
<p>With root access, you can install the stack your app actually needs: Nginx or Apache, Caddy, Node.js, Python, Go binaries, PHP, PostgreSQL, MySQL, Redis, Docker, queue workers, search tools, observability agents, cron jobs, private APIs, reverse proxies, VPN services, and internal tools.</p>
<p>That flexibility matters when the workload is no longer a plain website. A dashboard with background imports, a bot that listens all day, a webhook receiver, a small SaaS app, a staging server, or a private API all fit a VPS better than a restricted shared account.</p>
<p>Resources are usually more predictable. If the plan says 2 vCPU and 4 GB RAM, you can reason about capacity in a way that is harder on shared hosting. Virtualization is still shared at the physical host level, and providers vary, but the boundary is clearer. You can watch CPU, RAM, disk I/O, network use, and process behavior yourself.</p>
<p>Scaling is also more direct. You can move from a smaller VPS to a larger one, add a cache, split a database, move static assets to a CDN, run multiple services, or tune the web server for your workload. The path is not always one click, but it is usually under your control.</p>
<p>Dedicated IP addressing is another practical difference. A VPS often includes its own IPv4 address and IPv6 allocation. That can help with mail reputation separation, firewall allowlists, reverse proxy rules, custom SSL/network setups, and avoiding unrelated customers on the same address. It is not an automatic SEO boost. Search engines care more about crawlability, content, performance, and abuse signals than whether you bought a dedicated IP. Still, an address you control can make operations cleaner.</p>
<p>The limits are just as important.</p>
<p>With a VPS, security and operations become your job unless you pay for managed service. Someone has to patch the OS, lock down SSH, configure the firewall, rotate keys, monitor disk space, set up backups, renew certificates, tune the database, and recover from mistakes. If the server dies at 3am, the provider can usually tell you whether the VPS is powered on. It may not debug your Nginx config.</p>
<p>The “not optimally configured” point cuts both ways. An expert can tune a VPS better than a shared host’s generic environment. A novice can make a VPS slower, less secure, and less reliable than decent shared hosting. VPS value depends on the operator’s skill.</p>
<h2 id="vps-vs-shared-hosting-comparison">VPS vs shared hosting comparison<a href="#vps-vs-shared-hosting-comparison" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>


















































<table><thead><tr><th>Category</th><th>Shared hosting</th><th>VPS</th></tr></thead><tbody><tr><td>Control</td><td>Low to moderate. The provider controls most of the stack.</td><td>High. You control the operating system and services.</td></tr><tr><td>Performance predictability</td><td>Good enough for small sites, but hidden caps and neighbors can matter.</td><td>More predictable plan resources, with direct system metrics.</td></tr><tr><td>Software you can run</td><td>Usually PHP, static files, MySQL, and approved panel features.</td><td>Almost anything the OS can run, including Docker, queues, APIs, and custom daemons.</td></tr><tr><td>Scalability</td><td>Easy inside the provider’s plan tiers, weaker when the app needs custom architecture.</td><td>Better vertical scaling and more paths to split services later.</td></tr><tr><td>Security responsibility</td><td>Provider handles the server platform. You still handle app passwords, CMS updates, and code.</td><td>You handle OS, firewall, SSH, packages, services, and app security.</td></tr><tr><td>Ops time</td><td>Low. Most server work is hidden.</td><td>Medium to high, depending on automation and experience.</td></tr><tr><td>Cost structure</td><td>You pay for convenience and a managed environment.</td><td>You pay for resources and control, plus your own time.</td></tr><tr><td>Who it is for</td><td>Simple sites, small CMS projects, nontechnical owners, low-ops teams.</td><td>Developers, growing sites, custom apps, background services, teams needing control.</td></tr></tbody></table>
<h2 id="the-cost-myth">The cost myth<a href="#the-cost-myth" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Shared hosting is not always cheaper.</p>
<p>At the very low end, shared hosting wins on price. A small static site or basic WordPress install does not need a dedicated server environment, and paying more for control you will not use is wasteful.</p>
<p>The math changes when a site needs a little more resource. A better shared plan with higher CPU limits, more processes, staging, backups, malware scanning, and premium support can approach or exceed the monthly price of a modest VPS. At that point, the difference is not simply “cheap versus expensive.” It is “managed convenience versus control.”</p>
<p>Shared hosting bundles operations into the price. A VPS unbundles it. If you can run the server well, the VPS may give you more usable capacity per dollar. If you need someone else to manage everything, shared hosting or managed hosting may be the better value even at a higher sticker price.</p>
<h2 id="the-blurred-middle">The blurred middle<a href="#the-blurred-middle" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The line is not as clean as it used to be. Managed VPS plans, container platforms, PaaS products, and serverless hosting all borrow pieces from both models. They can be the right answer, but they are separate decisions. For this comparison, the useful split is still simple: shared hosting sells convenience; VPS sells control.</p>
<h2 id="how-to-choose">How to choose<a href="#how-to-choose" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Start with operations skill.</p>
<p>If you cannot SSH into a server, read logs, patch packages, and recover from a broken config, shared hosting is probably the safer first choice. That is not an insult. It means your time is better spent on the site, product, or content. If you can handle Linux basics, or you have someone who can, a VPS becomes realistic.</p>
<p>Next, look at the app type.</p>
<p>A plain PHP site, brochure site, small WordPress install, or static site can run happily on shared hosting. A Node.js app, Python API, Go service, Dockerized app, long-running bot, queue worker, custom database setup, or private tool usually points toward a VPS.</p>
<p>Then check traffic and resource behavior.</p>
<p>Light traffic with predictable pages is a shared hosting sweet spot. Traffic spikes, slow admin pages, heavy plugins, import jobs, expensive database queries, or repeated “resource limit reached” messages are signs that the shared environment is becoming the constraint. Before blaming the host, measure the layer that is slow. The guide on <a href="https://sa.net/blog/why-is-my-website-slow/" title="why is my website slow">why is my website slow</a> is a useful companion here because it separates hosting problems from app, payload, DNS, and rendering problems.</p>
<p>Finally, ask whether you need to run things beyond the website.</p>
<p>Email processing, bots, background jobs, API workers, WebSocket services, reverse proxies, VPN endpoints, analytics collectors, cron-heavy imports, and staging environments all push you toward VPS hosting. Shared hosting is strongest when the workload is a website. A VPS is stronger when the workload is a small system.</p>
<h2 id="when-it-is-time-to-move-to-a-vps">When it is time to move to a VPS<a href="#when-it-is-time-to-move-to-a-vps" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Move to a VPS when the shared hosting tradeoff stops helping.</p>
<p>Common upgrade signals are straightforward:</p>
<ul>
<li>you keep hitting CPU, memory, process, inode, or database limits</li>
<li>performance changes even when your own site has not changed</li>
<li>you need shell access for deployment or debugging</li>
<li>your app needs non-PHP software, background services, workers, or containers</li>
<li>you want a dedicated IP address or IPv6 allocation for cleaner network operations</li>
<li>traffic has grown enough that predictable resources matter</li>
<li>you need a staging or internal service beside the public site</li>
<li>the shared host’s panel is now shaping your architecture more than your app needs</li>
</ul>
<p>If the problem is performance, confirm the bottleneck first. The answer to “should I switch to a VPS” is yes only when shared hosting is the layer holding you back, or when your workload no longer fits the shared model.</p>
<p>When you reach that point, getting a VPS is the cleaner path. Riven Cloud is a solid option if you want a KVM VPS with a dedicated IPv4 address, a /64 IPv6 block, NVMe SSD storage, and a choice of Tokyo or Singapore node locations, and you can <a href="https://sa.net/pricing/" title="view VPS plans">view VPS plans</a> when you are ready to move.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>There is no absolute winner in VPS vs shared hosting.</p>
<p>Shared hosting is the better fit when convenience matters more than control. It keeps server work out of the way and gives many small sites exactly what they need. VPS hosting is the better fit when the application needs root access, predictable resources, custom software, background services, or a cleaner scaling path.</p>
<p>Match the hosting model to the stage of the project. A simple site can stay shared for a long time. A growing project usually trends toward a VPS because control starts to matter more than convenience.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="VPS" term="VPS"/>
        <category label="Infrastructure" term="Infrastructure"/>
        <category label="Hosting" term="Hosting"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why Is My Website Slow? Hosting or Something Else?]]></title>
        <id>https://sa.net/blog/why-is-my-website-slow/</id>
        <link href="https://sa.net/blog/why-is-my-website-slow/"/>
        <updated>2026-06-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A practical diagnostic guide for separating hosting bottlenecks from DNS, routing, caching, payload, and front-end problems.]]></summary>
        <content type="html"><![CDATA[<p>When someone asks, “why is my website slow?”, hosting is usually the first suspect. The reaction is understandable: the site feels slow, the server has a provider name on the invoice, and changing providers feels like a clean fix.</p>
<p>It is also a common way to waste a week.</p>
<p>A page load crosses several layers before a visitor can use the page: DNS, connection setup, TLS, server processing, content transfer, caching, and browser rendering. Slowness can live in any one of them. If the page is slow because of a 4 MB image, a blocking JavaScript bundle, or an uncached database query, moving the same site may change nothing.</p>
<p>The useful question is not “is my hosting slow?” The useful question is which layer is slow. Diagnose a slow website by isolating that layer first.</p>
<h2 id="mental-model-the-request-lifecycle">Mental model: the request lifecycle<a href="#mental-model-the-request-lifecycle" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>A browser does not load a page in one step. It walks through a chain of work:</p>
<ul>
<li>DNS resolution: the browser asks where the hostname points. Slow authoritative DNS, broken records, or bad TTL choices can delay the start.</li>
<li>TCP and TLS handshake: the browser opens a connection and negotiates encryption. Distance, routing, packet loss, old protocol support, and certificate setup can all show up here.</li>
<li>Server processing: the web server, application runtime, database, and upstream APIs produce the response. This is where slow TTFB often becomes visible.</li>
<li>Content download: HTML, images, CSS, JavaScript, fonts, and API responses move over the network. Large payloads and missing compression hurt here.</li>
<li>Browser rendering: the browser parses, styles, lays out, paints, and runs JavaScript. A fast server cannot save a front end that blocks the main thread.</li>
</ul>
<blockquote>
<p>Diagram placeholder: request lifecycle from browser to DNS resolver, TCP/TLS, web server, application/database, content download, and browser rendering.</p>
</blockquote>
<h2 id="why-is-my-website-slow-measure-before-guessing">Why is my website slow? Measure before guessing<a href="#why-is-my-website-slow-measure-before-guessing" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Start with a waterfall, not a score. Chrome DevTools documents the Network panel and its request timing view in its <a href="https://developer.chrome.com/docs/devtools/network/reference/" title="Network reference" target="_blank" rel="noopener noreferrer">Network reference</a>. Use it to separate waiting time, download time, and blocked rendering resources.</p>
<p><a href="https://pagespeed.web.dev/" title="PageSpeed Insights" target="_blank" rel="noopener noreferrer">PageSpeed Insights</a> and WebPageTest are useful, but read the waterfall before debating the score. The number at the top is a summary. The waterfall is the evidence.</p>
<blockquote>
<p>Screenshot placeholder: DevTools Network waterfall showing DNS, initial connection, TLS, waiting for server response, content download, and render-blocking CSS or JavaScript.</p>
</blockquote>
<p>Use the command line as a second view. <code>curl</code> exposes timing variables such as <code>time_namelookup</code>, <code>time_connect</code>, <code>time_appconnect</code>, <code>time_starttransfer</code>, and <code>time_total</code> in its <a href="https://curl.se/docs/manpage.html" title="write-out documentation" target="_blank" rel="noopener noreferrer">write-out documentation</a>.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;dns=%{time_namelookup}s tcp=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s bytes=%{size_download} http=%{http_code} proto=%{http_version}\n&#39;</span><span style="color:#9ECBFF"> https://example.com/</span></span></code></pre>
<p>Those times are cumulative from the start of the transfer. To estimate stage cost, subtract the previous stage. For example, TLS cost is roughly <code>time_appconnect - time_connect</code>, and server wait plus request time is roughly <code>time_starttransfer - time_appconnect</code> for HTTPS.</p>
<p>Then run the same test against a tiny static file and a dynamic page:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;ttfb=%{time_starttransfer}s total=%{time_total}s bytes=%{size_download}\n&#39;</span><span style="color:#9ECBFF"> https://example.com/favicon.ico</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;ttfb=%{time_starttransfer}s total=%{time_total}s bytes=%{size_download}\n&#39;</span><span style="color:#9ECBFF"> &#39;https://example.com/?probe=1&#39;</span></span></code></pre>
<p>That comparison is the fastest split in the whole investigation. If the static file has low TTFB but the dynamic page has high TTFB, your host may be fine and the app is probably slow. If both are slow from several networks, look harder at the host, origin network, CDN, or routing.</p>
<p>Add basic path checks:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ping</span><span style="color:#79B8FF"> -c</span><span style="color:#79B8FF"> 20</span><span style="color:#9ECBFF"> example.com</span></span>
<span class="line"><span style="color:#B392F0">traceroute</span><span style="color:#9ECBFF"> example.com</span></span>
<span class="line"><span style="color:#B392F0">mtr</span><span style="color:#79B8FF"> -rwzc</span><span style="color:#79B8FF"> 100</span><span style="color:#9ECBFF"> example.com</span></span></code></pre>
<p>Use MTR from the visitor region when possible. A test from your laptop only proves the path from your laptop.</p>
<h2 id="layer-by-layer-diagnosis">Layer-by-layer diagnosis<a href="#layer-by-layer-diagnosis" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<h3 id="dns-resolution">DNS resolution<a href="#dns-resolution" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> The page pauses before any connection starts. DevTools shows a long DNS phase, or <code>curl</code> reports high <code>time_namelookup</code>.</p>
<p><strong>How to test:</strong> Check authoritative records and resolver behavior:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">dig</span><span style="color:#9ECBFF"> example.com</span><span style="color:#9ECBFF"> A</span><span style="color:#9ECBFF"> +stats</span></span>
<span class="line"><span style="color:#B392F0">dig</span><span style="color:#9ECBFF"> example.com</span><span style="color:#9ECBFF"> AAAA</span><span style="color:#9ECBFF"> +stats</span></span>
<span class="line"><span style="color:#B392F0">dig</span><span style="color:#9ECBFF"> NS</span><span style="color:#9ECBFF"> example.com</span><span style="color:#9ECBFF"> +short</span></span>
<span class="line"><span style="color:#B392F0">dig</span><span style="color:#9ECBFF"> SOA</span><span style="color:#9ECBFF"> example.com</span><span style="color:#9ECBFF"> +short</span></span>
<span class="line"><span style="color:#B392F0">dig</span><span style="color:#9ECBFF"> +trace</span><span style="color:#9ECBFF"> example.com</span></span></code></pre>
<p>If one resolver is slow but another is normal, the problem may sit with a resolver path rather than your authoritative DNS. If authoritative nameservers are slow, misconfigured, or inconsistent, fix the DNS provider or registrar setup first.</p>
<p><strong>Verdict:</strong> Usually not the host. It is often the registrar, DNS provider, nameserver configuration, or resolver path. The host is involved only when it also runs your authoritative DNS.</p>
<h3 id="connection-and-tls">Connection and TLS<a href="#connection-and-tls" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> DNS finishes quickly, but the connection or TLS phase is long. Visitors far from the server complain more than visitors near the server.</p>
<p><strong>How to test:</strong> Compare TCP, TLS, and protocol support:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;tcp=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s proto=%{http_version}\n&#39;</span><span style="color:#9ECBFF"> https://example.com/</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -I</span><span style="color:#79B8FF"> --http2</span><span style="color:#9ECBFF"> https://example.com/</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -I</span><span style="color:#79B8FF"> --http3-only</span><span style="color:#9ECBFF"> https://example.com/</span></span></code></pre>
<p>The last command requires a curl build with HTTP/3 support. If it fails locally, use browser DevTools or an external test. MDN’s <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Evolution_of_HTTP" title="HTTP evolution guide" target="_blank" rel="noopener noreferrer">HTTP evolution guide</a> summarizes how HTTP/2 multiplexing and HTTP/3 over QUIC change connection behavior.</p>
<p>TLS overhead is rarely the whole problem on a warm connection, but repeated cold connections from distant regions add up. Certificate errors, missing session reuse, no HTTP/2, no HTTP/3, and no edge cache can make this layer worse than it should. If you are changing certificate configuration, verify the certificate chain, renewal path, redirects, and protocol support before blaming the host.</p>
<p><strong>Verdict:</strong> Mixed. Geographic distance is a node location problem. Routing quality and packet loss can be host-related. Certificate configuration and protocol support may be your web server or CDN configuration.</p>
<h3 id="server-response-and-ttfb">Server response and TTFB<a href="#server-response-and-ttfb" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> DNS, TCP, and TLS look reasonable, but <code>time_starttransfer</code> is high. DevTools shows a long “waiting for server response” phase. Users see a blank page before the first byte arrives.</p>
<p><strong>How to test:</strong> Compare static TTFB with dynamic TTFB from the same client:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -H</span><span style="color:#9ECBFF"> &#39;Cache-Control: no-cache&#39;</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;static_ttfb=%{time_starttransfer}s total=%{time_total}s\n&#39;</span><span style="color:#9ECBFF"> https://example.com/favicon.ico</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -H</span><span style="color:#9ECBFF"> &#39;Cache-Control: no-cache&#39;</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;dynamic_ttfb=%{time_starttransfer}s total=%{time_total}s\n&#39;</span><span style="color:#9ECBFF"> &#39;https://example.com/?uncached=1&#39;</span></span></code></pre>
<p>If both are slow, check the server itself:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">uptime</span></span>
<span class="line"><span style="color:#B392F0">free</span><span style="color:#79B8FF"> -m</span></span>
<span class="line"><span style="color:#B392F0">vmstat</span><span style="color:#79B8FF"> 1</span><span style="color:#79B8FF"> 10</span></span>
<span class="line"><span style="color:#B392F0">top</span><span style="color:#79B8FF"> -bn1</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> sed</span><span style="color:#79B8FF"> -n</span><span style="color:#9ECBFF"> &#39;1,5p&#39;</span></span></code></pre>
<p>On a VPS, sustained CPU steal while the instance is lightly loaded is a red flag. It means the hypervisor is not giving your virtual CPU the time it asked for. RAM pressure, swap churn, and disk wait can create the same user-visible symptom.</p>
<p>If the static file is fast and the dynamic page is slow, move up the stack. Check application logs, PHP-FPM status, slow database queries, cache misses, upstream API latency, and queue workers. In a WordPress, PHP, or custom app, one uncached page or slow SQL query can make the host look guilty.</p>
<p><strong>Verdict:</strong> Could be host or app. High TTFB on a tiny static file points toward host, origin network, CDN miss behavior, or web server configuration. High TTFB only on dynamic pages usually points to application code, database work, PHP/runtime limits, or cache misses.</p>
<h3 id="payload-size">Payload size<a href="#payload-size" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> TTFB is fine, but total load time is high. The waterfall shows large images, fonts, JavaScript bundles, CSS, or API responses taking most of the time.</p>
<p><strong>How to test:</strong> Look at transferred bytes in DevTools and compare compressed responses:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -D</span><span style="color:#9ECBFF"> -</span><span style="color:#79B8FF"> -H</span><span style="color:#9ECBFF"> &#39;Accept-Encoding: br,gzip&#39;</span><span style="color:#9ECBFF"> https://example.com/</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;bytes=%{size_download} total=%{time_total}s\n&#39;</span><span style="color:#9ECBFF"> https://example.com/</span></span></code></pre>
<p>Check for <code>content-encoding: br</code> or <code>content-encoding: gzip</code> on compressible text responses. MDN’s <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Compression" title="HTTP compression guide" target="_blank" rel="noopener noreferrer">HTTP compression guide</a> explains <code>Accept-Encoding</code> and response compression. For images, inspect dimensions and formats. A 3000 px image squeezed into a 360 px mobile slot is a content problem, not a VPS problem.</p>
<p><strong>Verdict:</strong> Not the host. Hosting can affect throughput, but unoptimized images, excessive JavaScript, unused CSS, and missing compression belong to the site build and delivery configuration.</p>
<h3 id="caching-and-cdn">Caching and CDN<a href="#caching-and-cdn" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> The first request is slow, repeat requests are faster, or every page hit regenerates dynamic content. Global visitors see inconsistent results.</p>
<p><strong>How to test:</strong> Inspect cache headers and repeat requests:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -I</span><span style="color:#9ECBFF"> https://example.com/</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -I</span><span style="color:#9ECBFF"> https://example.com/assets/app.css</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;ttfb=%{time_starttransfer}s total=%{time_total}s\n&#39;</span><span style="color:#9ECBFF"> https://example.com/</span></span>
<span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> /dev/null</span><span style="color:#79B8FF"> -sS</span><span style="color:#79B8FF"> -w</span><span style="color:#9ECBFF"> &#39;ttfb=%{time_starttransfer}s total=%{time_total}s\n&#39;</span><span style="color:#9ECBFF"> https://example.com/</span></span></code></pre>
<p>Look for <code>cache-control</code>, <code>etag</code>, <code>last-modified</code>, <code>age</code>, <code>vary</code>, and CDN-specific headers such as <code>x-cache</code>. A page cache can turn dynamic generation into a quick static response. A CDN can move static assets closer to users, but cache-busting query strings, <code>no-store</code> headers, and logged-in cookies can bypass it.</p>
<p><strong>Verdict:</strong> Host-adjacent and configuration-driven. The host may provide a cache or CDN integration, but the policy is usually yours: what can be cached, for how long, and whether dynamic pages are safe to cache.</p>
<h3 id="front-end-rendering">Front-end rendering<a href="#front-end-rendering" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> HTML arrives quickly, but the page still feels slow. DevTools shows long main-thread tasks, render-blocking CSS, large JavaScript execution time, layout shifts, or late-loading fonts.</p>
<p><strong>How to test:</strong> In DevTools, combine the Network panel with the Performance panel. Look for blocking scripts in the waterfall and long tasks during parse, style, layout, and paint. PageSpeed Insights can flag render-blocking resources and main-thread work, but confirm the finding in the trace rather than treating the score as the diagnosis.</p>
<p>Common fixes include deferring noncritical JavaScript, splitting bundles, removing unused CSS, preloading the right font files, setting image dimensions, and moving expensive work out of the critical path.</p>
<p><strong>Verdict:</strong> Not the host. A stronger CPU on the origin server will not reduce the JavaScript execution cost on a visitor’s phone.</p>
<h3 id="network-path-routing-and-peering">Network path, routing, and peering<a href="#network-path-routing-and-peering" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="##"></a></h3>
<p><strong>Symptom:</strong> The site is fast for you and slow for a specific country, ISP, office, or mobile carrier. TTFB may be acceptable near the data center and poor near the audience. Packet loss or route detours appear in MTR.</p>
<p><strong>How to test:</strong> Run path tests from the visitor geography, not only from your workstation:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">mtr</span><span style="color:#79B8FF"> -rwzc</span><span style="color:#79B8FF"> 100</span><span style="color:#9ECBFF"> example.com</span></span>
<span class="line"><span style="color:#B392F0">traceroute</span><span style="color:#9ECBFF"> example.com</span></span>
<span class="line"><span style="color:#B392F0">ping</span><span style="color:#79B8FF"> -c</span><span style="color:#79B8FF"> 50</span><span style="color:#9ECBFF"> example.com</span></span></code></pre>
<p>Ask users in the affected region to run the same tests, or use a Looking Glass near them. Compare routes by ASN and city, not just hop count. A physically close server can still take a poor carrier path. A farther server with better peering can sometimes behave better for the audience you care about. For planning, match the node location to the visitor geography you actually need to serve.</p>
<p><strong>Verdict:</strong> Host-related. Node location, carrier mix, transit quality, peering, and return path all belong to the hosting network decision. Your application code cannot fix a bad route to your main audience.</p>
<h2 id="so-is-it-actually-the-host">So is it actually the host?<a href="#so-is-it-actually-the-host" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Hosting is the proven bottleneck when the evidence points below the application layer.</p>
<p>Strong host signals include high TTFB on a tiny static file from multiple test networks, sustained CPU steal or disk wait on a lightly loaded VPS, RAM pressure that you did not create, packet loss on the path to the origin, or poor routing to your main visitor geography. Another common signal is the regional split: “fine for me, slow for visitors elsewhere.” That often means the node is in the wrong region or the network path is poor for that audience.</p>
<p>Weak host signals include a low PageSpeed score with huge images, slow dynamic pages while static files are fast, long JavaScript tasks after HTML arrives, or missing cache headers. Those problems can follow you to any provider.</p>













































<table><thead><tr><th>Signal</th><th>Likely host issue?</th><th>Why</th></tr></thead><tbody><tr><td>Tiny static file has high TTFB from several regions</td><td>Yes</td><td>Origin server, node network, CDN miss path, or overloaded VPS may be slow</td></tr><tr><td>Static file is fast but dynamic page TTFB is high</td><td>Usually no</td><td>Application, database, PHP/runtime, or upstream API work is slow</td></tr><tr><td>DNS lookup is slow or inconsistent</td><td>Usually no</td><td>Registrar, authoritative DNS provider, resolver path, or bad records are more likely</td></tr><tr><td>Large images or JavaScript dominate the waterfall</td><td>No</td><td>Payload and front-end build problems follow the site to any host</td></tr><tr><td>Repeat view is much faster than first view</td><td>Mixed</td><td>Caching policy, CDN, and application cache need review</td></tr><tr><td>Visitors in one region are slow while nearby users are fine</td><td>Often yes</td><td>Node location, peering, routing, and return path matter</td></tr><tr><td>CPU steal, disk wait, or swap churn appear under light load</td><td>Yes</td><td>Oversold VPS, noisy neighbor, or under-provisioned instance is plausible</td></tr></tbody></table>
<h2 id="decision-flowchart">Decision flowchart<a href="#decision-flowchart" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>Slow before connection starts</span></span>
<span class="line"><span>  -&gt; likely layer: DNS</span></span>
<span class="line"><span>  -&gt; fix: authoritative DNS, registrar records, resolver path, TTL policy</span></span>
<span class="line"><span></span></span>
<span class="line"><span>High TCP or TLS time</span></span>
<span class="line"><span>  -&gt; likely layer: distance, routing, protocol support, TLS config</span></span>
<span class="line"><span>  -&gt; fix: closer node, better route, HTTP/2 or HTTP/3, clean certificate setup</span></span>
<span class="line"><span></span></span>
<span class="line"><span>High TTFB on static and dynamic URLs</span></span>
<span class="line"><span>  -&gt; likely layer: host, origin web server, CDN miss path, routing</span></span>
<span class="line"><span>  -&gt; fix: inspect VPS load, CPU steal, disk wait, packet loss, node location</span></span>
<span class="line"><span></span></span>
<span class="line"><span>High TTFB only on dynamic URLs</span></span>
<span class="line"><span>  -&gt; likely layer: application or database</span></span>
<span class="line"><span>  -&gt; fix: page cache, query profiling, PHP/runtime tuning, upstream timeout review</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Low TTFB but high total load time</span></span>
<span class="line"><span>  -&gt; likely layer: payload</span></span>
<span class="line"><span>  -&gt; fix: compress text, resize images, reduce JS and CSS, cache assets</span></span>
<span class="line"><span></span></span>
<span class="line"><span>HTML arrives quickly but the page is still unusable</span></span>
<span class="line"><span>  -&gt; likely layer: front-end rendering</span></span>
<span class="line"><span>  -&gt; fix: remove render blockers, reduce main-thread work, defer noncritical scripts</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Slow only for one geography or carrier</span></span>
<span class="line"><span>  -&gt; likely layer: routing and peering</span></span>
<span class="line"><span>  -&gt; fix: choose a better node, test Looking Glass paths, use CDN or provider with better regional routing</span></span></code></pre>
<h2 id="when-changing-or-upgrading-hosting-genuinely-helps">When changing or upgrading hosting genuinely helps<a href="#when-changing-or-upgrading-hosting-genuinely-helps" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Changing providers helps when the host is the measured bottleneck: an oversold VPS with CPU steal, an instance without enough RAM or disk performance, a node far from your users, weak peering to the target region, no IPv6 where your audience benefits from it, no HTTP/3 or modern edge support in your delivery path, or an IP setup that does not fit the service.</p>
<p>If your measurements point to location or routing as the bottleneck, compare Riven Cloud’s <a href="https://sa.net/locations/" title="Tokyo and Singapore locations">Tokyo and Singapore locations</a> and <a href="https://sa.net/network/" title="network paths">network paths</a>. When those match your audience, you can <a href="https://sa.net/pricing/" title="view VPS plans">view VPS plans</a> or order from the <a href="https://portal.sa.net/store/cloud-server/" title="Riven Cloud portal" target="_blank" rel="noopener noreferrer">Riven Cloud portal</a>.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The next time the question is “why is my website slow?”, do not start with a provider migration. Start with the waterfall, split static from dynamic, check the path, and name the slow layer.</p>
<p>Switching hosts helps when hosting is the proven bottleneck. If DNS is broken, fix DNS. If the app is generating pages slowly, fix the app or cache it. If the payload is too large, shrink it. If the route to your users is bad, then hosting location and network quality become the right problem to solve.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="Network" term="Network"/>
        <category label="VPS" term="VPS"/>
        <category label="Infrastructure" term="Infrastructure"/>
        <category label="Performance" term="Performance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[What is CMIN2? China Mobile International N2 and AS58807 explained]]></title>
        <id>https://sa.net/blog/china-mobile-premium/</id>
        <link href="https://sa.net/blog/china-mobile-premium/"/>
        <updated>2026-06-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn what CMIN2 means, how China Mobile International N2 and AS58807 work, and how Riven Cloud routes Tokyo VPS traffic for China Mobile users.]]></summary>
        <content type="html"><![CDATA[<p>China Mobile is often the least understood part of China-optimized VPS routing.</p>
<p>Many buyers already know what to look for on China Telecom: CN2 GIA, CTGNet, AS4809, AS23764. They may also know China Unicom Premium through AS9929 and AS10099. China Mobile has its own premium path, and the signal to look for is CMIN2 / AS58807.</p>
<p>For China Mobile users, the route question is simple:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>Does traffic move from China Mobile AS9808 into CMIN2 / AS58807,</span></span>
<span class="line"><span>or does it fall back to ordinary CMI / AS58453 and standard international transit?</span></span></code></pre>
<p>For Riven Cloud Tokyo, the optimized China Mobile path in the June 29, 2026 sample was:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile access / regional network</span></span>
<span class="line"><span>-&gt; China Mobile domestic backbone / AS9808</span></span>
<span class="line"><span>-&gt; CMIN2 / China Mobile International N2 / AS58807</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>The ordinary SoftBank transit baseline from the same comparison set looked different:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile access / regional network</span></span>
<span class="line"><span>-&gt; China Mobile AS9808</span></span>
<span class="line"><span>-&gt; ordinary CMI / AS58453</span></span>
<span class="line"><span>-&gt; SoftBank AS17676</span></span>
<span class="line"><span>-&gt; AS3258 Tokyo endpoint</span></span></code></pre>
<p>That difference matters. A VPS can be in Japan and still take the wrong carrier path for China Mobile users.</p>
<h2 id="the-china-mobile-networks-customers-should-know">The China Mobile networks customers should know<a href="#the-china-mobile-networks-customers-should-know" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Mobile routing has several layers. For VPS buyers, four ASNs are worth knowing.</p>
<p><a href="https://bgp.he.net/AS9808" title="Hurricane Electric’s BGP Toolkit lists AS9808 as China Mobile Communications Group Co., Ltd." target="_blank" rel="noopener noreferrer">Hurricane Electric’s BGP Toolkit lists AS9808 as China Mobile Communications Group Co., Ltd.</a>. That is the domestic China Mobile backbone side. A user may start from a provincial or regional China Mobile network first, then enter AS9808.</p>
<p><a href="https://www.peeringdb.com/asn/58807" title="PeeringDB lists AS58807 as China Mobile International - NII" target="_blank" rel="noopener noreferrer">PeeringDB lists AS58807 as China Mobile International - NII</a>, with <code>CMIN2</code> as its also-known-as value. The same PeeringDB record shows AS58807 at Tokyo, Singapore, Hong Kong, Frankfurt, and other interconnection points. <a href="https://bgp.tools/as/58807" title="BGP.tools also lists AS58807 as China Mobile International Limited" target="_blank" rel="noopener noreferrer">BGP.tools also lists AS58807 as China Mobile International Limited</a>, with prefix descriptions such as Japan N2 Network, Singapore N2 Network, and Germany N2 Network.</p>
<p><a href="https://bgp.he.net/AS58453" title="Hurricane Electric’s BGP Toolkit lists AS58453 as China Mobile International Limited" target="_blank" rel="noopener noreferrer">Hurricane Electric’s BGP Toolkit lists AS58453 as China Mobile International Limited</a>. In the baseline route below, AS58453 appears as the ordinary CMI international side before SoftBank AS17676. <a href="https://www.peeringdb.com/asn/17676" title="PeeringDB lists AS17676 as SoftBank Corp." target="_blank" rel="noopener noreferrer">PeeringDB lists AS17676 as SoftBank Corp.</a>, and <a href="https://www.peeringdb.com/asn/3258" title="AS3258 as xTom Tokyo" target="_blank" rel="noopener noreferrer">AS3258 as xTom Tokyo</a>.</p>
<p>Use this practical map:</p>
<ul>
<li>China Mobile regional or access networks: where many broadband, enterprise, or mobile users begin.</li>
<li><code>AS9808</code>: China Mobile’s domestic backbone.</li>
<li><code>AS58807</code>: CMIN2 / China Mobile International N2, the premium international path.</li>
<li><code>AS58453</code>: ordinary China Mobile International / CMI, commonly seen on standard China Mobile international routes.</li>
<li><code>AS17676</code>: SoftBank, used in the standard transit baseline.</li>
<li><code>AS3258</code>: the Tokyo network used by the test endpoints.</li>
</ul>
<p>AS9808 is the domestic side. AS58807 is the premium CMIN2 international side. A strong China Mobile optimized route should show traffic moving from AS9808 into AS58807 before it reaches the VPS provider.</p>
<h2 id="what-cmin2-means">What CMIN2 means<a href="#what-cmin2-means" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CMIN2 means China Mobile International N2. In the VPS market, it is the premium China Mobile path customers should look for when evaluating China Mobile optimized connectivity.</p>
<p>It plays a similar customer-facing role for China Mobile users as CN2 GIA does for China Telecom users or CUP / AS9929 does for China Unicom users. It is not the same network and should not be described as the same product. The useful comparison is functional: it gives China Mobile traffic a carrier-matched premium path instead of pushing it through ordinary international transit.</p>
<p>For Riven Cloud, the shorthand is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile traffic from mainland China</span></span>
<span class="line"><span>-&gt; AS9808 domestically</span></span>
<span class="line"><span>-&gt; CMIN2 / AS58807 internationally</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>The old habit of checking only Telecom and Unicom is incomplete. If your users are on China Mobile broadband or China Mobile 5G, AS58807 is the route signal to check.</p>
<h2 id="cmin2--as58807-and-ordinary-cmi--as58453-are-not-the-same-route">CMIN2 / AS58807 and ordinary CMI / AS58453 are not the same route<a href="#cmin2--as58807-and-ordinary-cmi--as58453-are-not-the-same-route" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CMIN2 and ordinary CMI are related to China Mobile International, but they should not be treated as interchangeable.</p>
<p>AS58807 is the CMIN2 / N2 premium path. It is the AS Riven Cloud peers with for China Mobile optimized routing, and it is the desired path for China Mobile users accessing the Riven Cloud Tokyo optimized node.</p>
<p>AS58453 is the ordinary CMI path seen in the baseline route. It can be useful for general Internet traffic, but in this China Mobile to Tokyo sample it then handed traffic to SoftBank AS17676 before reaching AS3258.</p>
<p>That is the operational split:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>Optimized:</span></span>
<span class="line"><span>AS9808 -&gt; CMIN2 / AS58807 -&gt; AS3258</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Standard transit baseline:</span></span>
<span class="line"><span>AS9808 -&gt; ordinary CMI / AS58453 -&gt; SoftBank AS17676 -&gt; AS3258</span></span></code></pre>
<p>The names sound close enough to confuse people. The routes are visibly different.</p>
<h2 id="the-riven-cloud-china-mobile-cmin2-path">The Riven Cloud China Mobile CMIN2 path<a href="#the-riven-cloud-china-mobile-cmin2-path" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized path for China Mobile users is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile user</span></span>
<span class="line"><span>-&gt; China Mobile regional/access network</span></span>
<span class="line"><span>-&gt; China Mobile domestic backbone / AS9808</span></span>
<span class="line"><span>-&gt; CMIN2 / China Mobile International N2 / AS58807</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>Each part has a job:</p>
<ul>
<li>The user may start from a regional China Mobile access network, such as a provincial CMNET segment.</li>
<li>AS9808 is the China Mobile domestic backbone.</li>
<li>AS58807 is CMIN2 / China Mobile International N2.</li>
<li>AS3258 is the Tokyo network used by the Riven Cloud optimized test node.</li>
</ul>
<p>Riven Cloud peers with China Mobile through CMIN2 / AS58807. China Mobile traffic from mainland China uses AS9808 domestically before reaching CMIN2 / AS58807, then Riven Cloud.</p>
<h2 id="optimized-route-mtr-sample">Optimized route MTR sample<a href="#optimized-route-mtr-sample" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized mainland China to Tokyo sample came from a third-party MTR-style capture with 20 probes. The return MTR from Tokyo to mainland China started at <code>2026-06-29T10:34:03+0000</code> and used 10 probes.</p>
<p>The forward sample showed a China Mobile regional access side, AS9808, CMIN2 / AS58807, and the final Riven Cloud endpoint on AS3258. The return sample showed AS3258, then AS58807, then AS9808, then the China Mobile access endpoint.</p>


























<table><thead><tr><th>Direction</th><th>Visible premium path</th><th style="text-align:right">Final-hop avg RTT</th><th style="text-align:right">Best RTT</th><th style="text-align:right">Final-hop packet loss</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td>China Mobile access -&gt; AS9808 -&gt; CMIN2/AS58807 -&gt; AS3258</td><td style="text-align:right">40.0 ms</td><td style="text-align:right">39.8 ms</td><td style="text-align:right">0.0%</td></tr><tr><td>Tokyo to mainland China</td><td>AS3258 -&gt; CMIN2/AS58807 -&gt; AS9808 -&gt; China Mobile access</td><td style="text-align:right">44.7 ms</td><td style="text-align:right">44.6 ms</td><td style="text-align:right">0.0%</td></tr></tbody></table>
<p>The optimized route shows the expected China Mobile premium structure in both directions. Traffic moves between AS9808 and CMIN2 / AS58807, instead of using ordinary CMI and standard transit.</p>
<h2 id="standard-softbank-transit-comparison">Standard SoftBank transit comparison<a href="#standard-softbank-transit-comparison" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The same June 29, 2026 comparison set included a standard SoftBank transit baseline to an AS3258 Tokyo endpoint. It was not the same destination IP as the Riven Cloud optimized node, so treat it as a route-pattern baseline rather than a same-host A/B test.</p>
<p>The baseline path was:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile user</span></span>
<span class="line"><span>-&gt; China Mobile regional/access network</span></span>
<span class="line"><span>-&gt; China Mobile AS9808</span></span>
<span class="line"><span>-&gt; ordinary CMI / AS58453</span></span>
<span class="line"><span>-&gt; SoftBank AS17676</span></span>
<span class="line"><span>-&gt; AS3258 Tokyo endpoint</span></span></code></pre>
<p>Cleaned final-hop results from that baseline were:</p>


























<table><thead><tr><th>Direction</th><th>Standard transit path</th><th style="text-align:right">Final-hop avg RTT</th><th style="text-align:right">Best RTT</th><th style="text-align:right">Final-hop packet loss</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td>AS9808 -&gt; ordinary CMI/AS58453 -&gt; SoftBank/AS17676 -&gt; AS3258</td><td style="text-align:right">72.2 ms</td><td style="text-align:right">72.0 ms</td><td style="text-align:right">0.0%</td></tr><tr><td>Tokyo to mainland China</td><td>AS3258 -&gt; SoftBank/AS17676 -&gt; ordinary CMI/AS58453 -&gt; AS9808</td><td style="text-align:right">70.0 ms</td><td style="text-align:right">69.9 ms</td><td style="text-align:right">0.0%</td></tr></tbody></table>
<p>This does not mean SoftBank or ordinary CMI is bad. They can be fine for many general routes. For this China Mobile to Tokyo sample, the standard transit path had much higher average RTT than the CMIN2 optimized path.</p>
<h2 id="side-by-side-results">Side-by-side results<a href="#side-by-side-results" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The CMIN2 optimized path reduced average RTT in both directions.</p>


























<table><thead><tr><th>Direction</th><th style="text-align:right">Standard transit avg RTT</th><th style="text-align:right">CMIN2 optimized avg RTT</th><th style="text-align:right">Reduction</th><th>Optimized path</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td style="text-align:right">72.2 ms</td><td style="text-align:right">40.0 ms</td><td style="text-align:right">32.2 ms lower / about 45% lower</td><td>AS9808 -&gt; CMIN2/AS58807</td></tr><tr><td>Tokyo to mainland China</td><td style="text-align:right">70.0 ms</td><td style="text-align:right">44.7 ms</td><td style="text-align:right">25.3 ms lower / about 36% lower</td><td>CMIN2/AS58807 -&gt; AS9808</td></tr></tbody></table>
<p>The latency reduction is useful. The path evidence is the bigger point: the optimized route used AS58807, the intended China Mobile premium path, instead of ordinary CMI / AS58453 and standard international transit.</p>
<p>For China Mobile customers, this is the missing piece in many route comparisons. Telecom may have CN2/CTGNet. Unicom may have AS9929/AS10099. Mobile needs its own premium path too.</p>
<h2 id="why-cmin2-matters-for-china-mobile-users">Why CMIN2 matters for China Mobile users<a href="#why-cmin2-matters-for-china-mobile-users" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Mobile users were often the weak spot in older “China optimized” VPS offers. A provider might optimize for China Telecom and China Unicom, then leave China Mobile to ordinary international routing.</p>
<p>CMIN2 changes the checklist. China Mobile users can now look for a premium path of their own: AS9808 on the domestic side, AS58807 on the international side, then the provider network.</p>
<p>In practical terms, that can mean:</p>
<ul>
<li>Lower latency for China Mobile users.</li>
<li>More responsive SSH sessions.</li>
<li>Faster website loading from China Mobile networks.</li>
<li>Better API response times from mainland China.</li>
<li>Smoother control panel or remote desktop access.</li>
<li>Less dependence on ordinary transit paths.</li>
<li>Better carrier matching for services with China Mobile users.</li>
</ul>
<p>The route does not make every application fast. It removes one common source of delay: sending China Mobile traffic through a less suitable international path.</p>
<h2 id="how-to-check-whether-a-route-is-really-cmin2">How to check whether a route is really CMIN2<a href="#how-to-check-whether-a-route-is-really-cmin2" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>A CMIN2 route should usually show:</p>
<ul>
<li>AS9808 on the mainland China domestic side.</li>
<li>AS58807 on the China Mobile International N2 side.</li>
<li>The provider AS after AS58807.</li>
</ul>
<p>For Riven Cloud Tokyo, the expected optimized pattern is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China to Tokyo:</span></span>
<span class="line"><span>China Mobile access -&gt; AS9808 -&gt; AS58807 -&gt; AS3258</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Tokyo to China:</span></span>
<span class="line"><span>AS3258 -&gt; AS58807 -&gt; AS9808 -&gt; China Mobile access</span></span></code></pre>
<p>The ordinary baseline pattern may look like this:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile access -&gt; AS9808 -&gt; AS58453 -&gt; AS17676 -&gt; AS3258</span></span></code></pre>
<p>Router IPs and city codes can change. The AS-level pattern is the part to check first.</p>
<h2 id="how-to-read-mtr-without-chasing-noise">How to read MTR without chasing noise<a href="#how-to-read-mtr-without-chasing-noise" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>MTR is useful, but it is not a packet-loss oracle.</p>
<p>Intermediate routers may rate-limit ICMP, ignore probes, or show strange control-plane latency while still forwarding customer traffic normally. A 100% non-response on an intermediate hop does not prove end-to-end packet loss when later hops and the final destination continue to respond.</p>
<p>The optimized return sample is a good example. Several early AS3258 intermediate hops reported high latency or loss-like behavior, but later AS58807, AS9808, and final access-network hops were normal. The final destination showed 44.7 ms average RTT, 44.6 ms best RTT, and 0.0% packet loss.</p>
<p>When checking CMIN2 routes, focus on:</p>
<ul>
<li>Final-hop average RTT.</li>
<li>Final-hop packet loss.</li>
<li>Whether the path shows AS9808 and AS58807.</li>
<li>Whether the return direction also uses AS58807 and AS9808.</li>
<li>Whether intermediate loss continues to the final destination.</li>
</ul>
<p>Short MTR samples are useful route evidence. They are not an SLA for every province, every hour, or every future routing change.</p>
<h2 id="what-cmin2-cannot-guarantee">What CMIN2 cannot guarantee<a href="#what-cmin2-cannot-guarantee" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CMIN2 gives China Mobile traffic a better path. It does not make every last-mile network perfect.</p>
<p>Performance can still depend on province, local China Mobile access quality, home broadband or 5G conditions, time of day, carrier routing changes, international cable incidents, firewall behavior, application protocol, customer-side Wi-Fi, and router quality.</p>
<p>CMIN2 also cannot make all mobile networks behave like fiber broadband. A phone on a congested cell, a home router with poor Wi-Fi, or an application with bad retry behavior can still feel slow.</p>
<p>Treat the route as one part of the deployment decision, alongside CPU, RAM, NVMe storage, monthly transfer, backup policy, and application design.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>For China Mobile users, Riven Cloud’s optimized Tokyo route is designed around the CMIN2 premium path:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Mobile access / regional network</span></span>
<span class="line"><span>-&gt; AS9808 domestic backbone</span></span>
<span class="line"><span>-&gt; CMIN2 / China Mobile International N2 / AS58807</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>In the June 29, 2026 samples, that path delivered 40.0 ms average RTT from mainland China to Tokyo and 44.7 ms average RTT from Tokyo back to mainland China, both with 0.0% final-hop packet loss.</p>
<p>The standard SoftBank transit baseline averaged 72.2 ms from mainland China to Tokyo and 70.0 ms in the return direction. The cleaner result came from the path choice: AS9808 into CMIN2 / AS58807 instead of AS58453 and SoftBank transit.</p>
<p>For the full three-network view, read <a href="https://sa.net/blog/what-are-china-optimized-routes/" title="What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained">What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained</a>. For the other carrier-specific articles, see <a href="https://sa.net/blog/china-telecom-premium/" title="China Telecom premium routing">China Telecom premium routing</a> and <a href="https://sa.net/blog/china-unicom-premium/" title="China Unicom Premium routing">China Unicom Premium routing</a>.</p>
<p>If your users are on China Mobile in mainland China, test the path from the <a href="https://tok-premium.lg.xtom.com/" title="Tokyo Looking Glass" target="_blank" rel="noopener noreferrer">Tokyo Looking Glass</a> and compare it with your current route. If the CMIN2 path fits your users, <a href="https://sa.net/pricing/" title="view the Riven Cloud VPS plans">view the Riven Cloud VPS plans</a> and deploy a Tokyo server built for China Mobile traffic to take the right carrier path before it reaches your application.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="China Mobile" term="China Mobile"/>
        <category label="CMIN2" term="CMIN2"/>
        <category label="AS58807" term="AS58807"/>
        <category label="AS9808" term="AS9808"/>
        <category label="China-optimized VPS" term="China-optimized VPS"/>
        <category label="Routing" term="Routing"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[What is CTGNet / CN2 GIA? China Telecom AS4809 and AS23764 explained]]></title>
        <id>https://sa.net/blog/china-telecom-premium/</id>
        <link href="https://sa.net/blog/china-telecom-premium/"/>
        <updated>2026-06-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn how China Telecom premium routing works, why CTGNet and CN2 GIA are different parts of the path, and how Riven Cloud routes Tokyo VPS traffic for China Telecom users.]]></summary>
        <content type="html"><![CDATA[<p>Many VPS providers advertise “CN2,” “CN2 GIA,” or “China Telecom optimized.” The label is easy to print on a product page. The path is harder to fake.</p>
<p>For China Telecom users, the useful question is whether traffic uses the premium China Telecom route in both directions: the China Telecom access network, the CN2/AS4809 premium segment, the current CTGNet/AS23764 international delivery path, and then the VPS provider network.</p>
<p>For Riven Cloud Tokyo, the optimized China Telecom path is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Telecom access network / AS4134</span></span>
<span class="line"><span>-&gt; CN2 premium segment / AS4809 / 59.43</span></span>
<span class="line"><span>-&gt; CTGNet international edge / AS23764</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>That is materially different from a normal international transit path such as:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Telecom AS4134</span></span>
<span class="line"><span>-&gt; SoftBank AS17676</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>The MTR samples in this article were collected on June 29, 2026. They are short samples, not an SLA. They are useful because they show both the visible AS path and the final-hop behavior for the optimized China Telecom route, then compare it with a standard SoftBank transit baseline from the same test set.</p>
<h2 id="china-telecom-routing-has-several-moving-parts">China Telecom routing has several moving parts<a href="#china-telecom-routing-has-several-moving-parts" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Telecom routing is easy to oversimplify because several related names show up in the same conversation.</p>
<p><a href="https://www.chinatelecomasiapacific.com/global-internet-access" title="China Telecom’s Global Internet Access page" target="_blank" rel="noopener noreferrer">China Telecom’s Global Internet Access page</a> says the service offers access to ChinaNet (AS4134) and CN2 (AS4809). Public PeeringDB records list <a href="https://www.peeringdb.com/asn/23764" title="CTGNet as AS23764" target="_blank" rel="noopener noreferrer">CTGNet as AS23764</a> with the IRR as-set <code>AS-CTGNET</code>, and <a href="https://www.peeringdb.com/asn/4809" title="China Telecom / CN2 as AS4809" target="_blank" rel="noopener noreferrer">China Telecom / CN2 as AS4809</a> with the IRR as-set <code>AS-CN2</code>.</p>
<p>For VPS buyers, the practical map looks like this:</p>
<ul>
<li><code>AS4134</code>: ChinaNet / China Telecom’s large public Internet backbone and access network.</li>
<li><code>AS4809</code>: CN2 / China Telecom’s premium backbone segment, commonly associated with CN2 GIA in the VPS market.</li>
<li><code>AS23764</code>: CTGNet / China Telecom Global’s international network used for peering and international delivery.</li>
</ul>
<p>A China Telecom broadband user may begin in AS4134 or a regional access network. A premium route should move the traffic into the CN2/AS4809 segment and then use CTGNet/AS23764 for the international handoff.</p>
<p>That last point is where many route descriptions get sloppy. CTGNet and CN2 GIA are related in how customers experience the route, but they are not interchangeable terms.</p>
<h2 id="what-cn2-gia-means-in-practice">What CN2 GIA means in practice<a href="#what-cn2-gia-means-in-practice" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CN2 GIA is market shorthand for China Telecom’s premium global Internet access route. VPS buyers usually associate it with the CN2/AS4809 backbone, lower latency, less congestion, and more predictable cross-border performance than ordinary ChinaNet routes.</p>
<p>The label alone does not prove much. A useful route check asks two questions:</p>
<ul>
<li>Does the route show the premium CN2 segment, often visible as <code>59.43</code> hops or AS4809?</li>
<li>Does the international handoff avoid ordinary transit and land on the intended China Telecom Global path?</li>
</ul>
<p>In practice, customers should look less at the label and more at the path. A trace that says “CN2” somewhere in the middle is weaker evidence than a clean path showing China Telecom access, CN2/AS4809, CTGNet/AS23764, and the provider network in both directions.</p>
<h2 id="what-ctgnet-means-in-this-route">What CTGNet means in this route<a href="#what-ctgnet-means-in-this-route" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CTGNet is the China Telecom Global international network associated with AS23764. In the Riven Cloud Tokyo route, CTGNet is the peer-facing international side of the China Telecom path.</p>
<p>CN2/AS4809 is the premium China Telecom segment that mainland China users have historically associated with CN2 GIA. CTGNet/AS23764 is the international delivery and interconnection side used in the current route.</p>
<p>Riven Cloud peers with China Telecom through CTGNet / AS23764. China Telecom traffic from mainland China uses the CN2 / AS4809 premium segment before reaching CTGNet / AS23764, where it is handed to Riven Cloud’s Tokyo network on AS3258. PeeringDB lists <a href="https://www.peeringdb.com/asn/3258" title="AS3258 as xTom Tokyo" target="_blank" rel="noopener noreferrer">AS3258 as xTom Tokyo</a>, which matches the Tokyo network context for this service.</p>
<p>The clean shorthand is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>AS4134 access</span></span>
<span class="line"><span>-&gt; CN2 / AS4809 / 59.43</span></span>
<span class="line"><span>-&gt; CTGNet / AS23764</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<h2 id="the-riven-cloud-china-telecom-path">The Riven Cloud China Telecom path<a href="#the-riven-cloud-china-telecom-path" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized path from a China Telecom user to Riven Cloud Tokyo should show the China Telecom access side first, then the premium CN2 segment, then CTGNet, then the Riven Cloud endpoint.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Telecom user</span></span>
<span class="line"><span>-&gt; China Telecom access network / AS4134</span></span>
<span class="line"><span>-&gt; CN2 premium segment / AS4809 / 59.43</span></span>
<span class="line"><span>-&gt; CTGNet international edge / AS23764</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>Each part has a job:</p>
<ul>
<li>AS4134 is where many ordinary China Telecom users begin.</li>
<li>The <code>59.43</code> hops indicate the CN2 premium segment.</li>
<li>CTGNet / AS23764 is the international handoff and China Telecom peer path.</li>
<li>AS3258 is the Tokyo network used by the Riven Cloud test node.</li>
</ul>
<p>The reverse direction matters as much as the forward direction. A route can look good from China to Tokyo and still return through a different, less suitable path. The Riven Cloud sample below showed the expected CTGNet and CN2 path in both directions.</p>
<h2 id="optimized-route-mtr-sample">Optimized route MTR sample<a href="#optimized-route-mtr-sample" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized MTR samples were collected on June 29, 2026 at <code>2026-06-29T10:22:04+0000</code> for mainland China to Tokyo and <code>2026-06-29T10:23:28+0000</code> for Tokyo to mainland China. Each sample used 10 probes.</p>
<p>The raw output showed China Telecom AS4134 near the access side, multiple <code>59.43</code> hops on the CN2 segment, CTGNet hostnames such as <code>ct163.jp.tyo.ctgnet</code> and <code>jp.tyo.ctgnet</code>, and the final Riven Cloud Tokyo endpoint on AS3258.</p>


























<table><thead><tr><th>Direction</th><th>Visible premium path</th><th style="text-align:right">Final-hop avg RTT</th><th style="text-align:right">Best RTT</th><th style="text-align:right">Final-hop packet loss</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td>AS4134 -&gt; CN2/59.43/AS4809 -&gt; CTGNet/AS23764 -&gt; AS3258</td><td style="text-align:right">36.3 ms</td><td style="text-align:right">36.1 ms</td><td style="text-align:right">0.0%</td></tr><tr><td>Tokyo to mainland China</td><td>AS3258 -&gt; CTGNet/AS23764 -&gt; CN2/59.43/AS4809 -&gt; AS4134</td><td style="text-align:right">41.6 ms</td><td style="text-align:right">41.6 ms</td><td style="text-align:right">0.0%</td></tr></tbody></table>
<p>The optimized route shows the expected premium China Telecom path in both directions. Traffic does not simply exit China Telecom through ordinary international transit. It uses the CN2/59.43 segment and CTGNet/AS23764 before reaching the Riven Cloud Tokyo network.</p>
<h2 id="standard-softbank-transit-comparison">Standard SoftBank transit comparison<a href="#standard-softbank-transit-comparison" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>SoftBank is a normal international transit path. PeeringDB lists <a href="https://www.peeringdb.com/asn/17676" title="SoftBank Corp. as AS17676" target="_blank" rel="noopener noreferrer">SoftBank Corp. as AS17676</a>. There is nothing inherently wrong with using SoftBank for general Internet traffic.</p>
<p>For this China Telecom to Tokyo comparison, the baseline path was less suitable:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Telecom user</span></span>
<span class="line"><span>-&gt; China Telecom AS4134</span></span>
<span class="line"><span>-&gt; SoftBank AS17676</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>The standard transit baseline from the same June 29, 2026 test set showed higher final-hop RTT than the CTGNet/CN2 optimized path.</p>


























<table><thead><tr><th>Direction</th><th>Standard transit path</th><th style="text-align:right">Final-hop avg RTT</th><th style="text-align:right">Best RTT</th><th style="text-align:right">Final-hop packet loss</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td>AS4134 -&gt; SoftBank/AS17676 -&gt; AS3258</td><td style="text-align:right">78.1 ms</td><td style="text-align:right">69.6 ms</td><td style="text-align:right">30.0% in this short sample</td></tr><tr><td>Tokyo to mainland China</td><td>AS3258 -&gt; SoftBank/AS17676 -&gt; AS4134</td><td style="text-align:right">74.1 ms</td><td style="text-align:right">63.1 ms</td><td style="text-align:right">10.0% in this short sample</td></tr></tbody></table>
<p>This sample does not prove that SoftBank is bad. It shows the difference between a generic international transit path and a China Telecom matched premium path for this specific Tokyo VPS use case.</p>
<h2 id="side-by-side-results">Side-by-side results<a href="#side-by-side-results" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The RTT gap was large in both directions.</p>


























<table><thead><tr><th>Direction</th><th style="text-align:right">Standard transit avg RTT</th><th style="text-align:right">CTGNet/CN2 optimized avg RTT</th><th style="text-align:right">Reduction</th><th>Optimized path</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td style="text-align:right">78.1 ms</td><td style="text-align:right">36.3 ms</td><td style="text-align:right">41.8 ms lower / about 54% lower</td><td>CN2/AS4809 -&gt; CTGNet/AS23764</td></tr><tr><td>Tokyo to mainland China</td><td style="text-align:right">74.1 ms</td><td style="text-align:right">41.6 ms</td><td style="text-align:right">32.5 ms lower / about 44% lower</td><td>CTGNet/AS23764 -&gt; CN2/AS4809</td></tr></tbody></table>
<p>In this sample, the CTGNet/CN2 optimized route reduced average RTT by more than 40 ms in the China-to-Tokyo direction and more than 30 ms in the return direction. The path itself is the more important signal: the optimized route used the intended China Telecom premium network instead of ordinary international transit.</p>
<p>That route choice is what customers should evaluate when they compare CN2 GIA VPS offers. A low number in one ping test is useful. A clean premium carrier path in both directions is better evidence.</p>
<h2 id="what-customers-feel">What customers feel<a href="#what-customers-feel" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Most customers do not buy AS paths for their own sake. They care whether a server feels usable from mainland China.</p>
<p>For China Telecom users, a better matched route can show up in practical ways:</p>
<ul>
<li>SSH sessions feel more responsive.</li>
<li>Control panels and dashboards spend less time waiting on the network.</li>
<li>API calls from mainland China have lower round-trip delay.</li>
<li>Websites load faster for China Telecom users.</li>
<li>Real-time applications have less room for jitter to become visible.</li>
<li>Evening peak is less likely to be dominated by ordinary international transit congestion.</li>
</ul>
<p>The word “likely” matters. Route optimization improves the path. It does not make every application fast, and it does not remove every local access problem.</p>
<h2 id="how-to-read-mtr-without-fooling-yourself">How to read MTR without fooling yourself<a href="#how-to-read-mtr-without-fooling-yourself" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>MTR is useful, but it is easy to overread.</p>
<p>Focus on the final destination, the overall RTT pattern, and the visible AS path. Intermediate packet loss can be caused by ICMP rate limiting, router control-plane protection, or devices that simply do not answer probes. A 100% non-response on an intermediate hop does not prove end-to-end loss when later hops and the final destination still respond normally.</p>
<p>For this comparison, the important checks are:</p>
<ul>
<li>Final-hop average RTT.</li>
<li>Final-hop packet loss.</li>
<li>Whether the visible path uses CN2/59.43/AS4809.</li>
<li>Whether the international handoff uses CTGNet/AS23764.</li>
<li>Whether the return path also uses the premium China Telecom route.</li>
</ul>
<p>Short MTR samples are useful route evidence. They are not a guarantee for every province, every hour, or every future carrier policy change.</p>
<h2 id="what-ctgnetcn2-cannot-guarantee">What CTGNet/CN2 cannot guarantee<a href="#what-ctgnetcn2-cannot-guarantee" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Premium China Telecom routing gives traffic a better path. It does not suspend the laws of the Internet.</p>
<p>Performance can still depend on the user’s province, local access network, time of day, submarine cable events, carrier routing changes, firewall behavior, application protocol, customer-side Wi-Fi, and last-mile conditions.</p>
<p>A clean CTGNet/CN2 path reduces dependence on ordinary international transit. It cannot control every hop before the user reaches China Telecom’s backbone, and it cannot guarantee that every application will use the network efficiently.</p>
<p>Treat route optimization as one important part of a deployment decision, alongside CPU, RAM, NVMe storage, transfer quota, backup policy, and application design.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>For China Telecom users, Riven Cloud’s optimized Tokyo route is built around the premium China Telecom path:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>AS4134 access network</span></span>
<span class="line"><span>-&gt; CN2 / AS4809 premium segment</span></span>
<span class="line"><span>-&gt; CTGNet / AS23764 international delivery</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>The June 29, 2026 sample showed much lower average RTT than ordinary SoftBank transit in both directions: 36.3 ms versus 78.1 ms from mainland China to Tokyo, and 41.6 ms versus 74.1 ms from Tokyo back to mainland China.</p>
<p>CTGNet and CN2 should be read as parts of the current China Telecom premium routing path, not as interchangeable words. The useful question is whether the actual path shows the premium China Telecom network in both directions.</p>
<p>For a broader carrier view, read <a href="https://sa.net/blog/what-are-china-optimized-routes/" title="What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained">What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained</a>. For the other carrier-specific articles, see <a href="https://sa.net/blog/china-unicom-premium/" title="China Unicom Premium routing">China Unicom Premium routing</a> and <a href="https://sa.net/blog/china-mobile-premium/" title="China Mobile CMIN2 routing">China Mobile CMIN2 routing</a>. To test from Riven Cloud’s Tokyo location, use the <a href="https://tok-premium.lg.xtom.com/" title="Tokyo Looking Glass" target="_blank" rel="noopener noreferrer">Tokyo Looking Glass</a>.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="China Telecom" term="China Telecom"/>
        <category label="CTGNet" term="CTGNet"/>
        <category label="CN2 GIA" term="CN2 GIA"/>
        <category label="AS4809" term="AS4809"/>
        <category label="AS23764" term="AS23764"/>
        <category label="China-optimized VPS" term="China-optimized VPS"/>
        <category label="Routing" term="Routing"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[What is China Unicom Premium? CUP, AS9929, and AS10099 explained]]></title>
        <id>https://sa.net/blog/china-unicom-premium/</id>
        <link href="https://sa.net/blog/china-unicom-premium/"/>
        <updated>2026-06-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn how China Unicom Premium routing works, how AS9929 and AS10099 fit together, and how Riven Cloud routes Tokyo VPS traffic for China Unicom users.]]></summary>
        <content type="html"><![CDATA[<p>Many VPS buyers check China Unicom routing by looking for AS9929. That is a good start, but it is not the full check.</p>
<p>China Unicom Premium, often called CUP in the VPS market, is better understood as a two-part premium path:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Unicom access / AS4837</span></span>
<span class="line"><span>-&gt; China Unicom Premium / AS9929</span></span>
<span class="line"><span>-&gt; China Unicom Global / AS10099</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>The value of the route is in that structure. A good China Unicom Premium path should move traffic from the normal AS4837 access or regional side into AS9929, then use China Unicom Global AS10099 for international delivery before reaching Riven Cloud.</p>
<p>For Riven Cloud Tokyo, the optimized Unicom path in the June 29, 2026 MTR samples was:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>Mainland China to Tokyo:</span></span>
<span class="line"><span>AS4837 -&gt; AS9929 -&gt; AS10099 -&gt; AS3258</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Tokyo to mainland China:</span></span>
<span class="line"><span>AS3258 -&gt; AS10099 -&gt; AS9929 -&gt; AS4837</span></span></code></pre>
<p>Those two directions matter. A route that shows AS9929 in one direction and ordinary transit in the other direction is not the same operational result.</p>
<h2 id="the-china-unicom-networks-customers-should-know">The China Unicom networks customers should know<a href="#the-china-unicom-networks-customers-should-know" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Unicom routing usually involves three ASNs in this discussion.</p>
<p><a href="https://kr.chinaunicomglobal.com/products-dia.php" title="China Unicom Global’s DIA page" target="_blank" rel="noopener noreferrer">China Unicom Global’s DIA page</a> describes AS4837 as China Unicom’s backbone Internet network and says its mainland China DIA service can use the premium bearer network AS9929. The same page describes AS9929 as light loaded and better performing for premium DIA. Its <a href="https://kr.chinaunicomglobal.com/products-ipt-and-peering.php" title="IPT &amp; peering page" target="_blank" rel="noopener noreferrer">IPT &amp; peering page</a> describes AS10099 as China Unicom’s international network for flexible usage patterns and customized routes.</p>
<p>Public PeeringDB records also match the ASN identities: <a href="https://www.peeringdb.com/asn/10099" title="AS10099 is China Unicom Global" target="_blank" rel="noopener noreferrer">AS10099 is China Unicom Global</a>, <a href="https://www.peeringdb.com/asn/9929" title="AS9929 is China Unicom Industrial Internet Backbone" target="_blank" rel="noopener noreferrer">AS9929 is China Unicom Industrial Internet Backbone</a>, and <a href="https://www.peeringdb.com/asn/3258" title="AS3258 is xTom Tokyo" target="_blank" rel="noopener noreferrer">AS3258 is xTom Tokyo</a>.</p>
<p>For route analysis, use this practical map:</p>
<ul>
<li><code>AS4837</code>: China Unicom’s common public Internet backbone and access or regional network.</li>
<li><code>AS9929</code>: the premium Unicom bearer segment, usually the part VPS buyers look for when checking a CUP route.</li>
<li><code>AS10099</code>: China Unicom Global’s international network and the peer-facing side for Riven Cloud.</li>
<li><code>AS3258</code>: the Tokyo network used by the Riven Cloud test node.</li>
</ul>
<p>AS4837 at the beginning of a trace is not a red flag by itself. Many Unicom users begin there. The route becomes interesting when traffic moves from AS4837 into AS9929, then reaches AS10099 before the provider network.</p>
<h2 id="what-china-unicom-premium-means-in-practice">What China Unicom Premium means in practice<a href="#what-china-unicom-premium-means-in-practice" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Unicom Premium is the market name commonly used for the premium Unicom cross-border route. In practice, a strong CUP route usually means AS9929 on the mainland China side and China Unicom Global AS10099 on the international side.</p>
<p>The name alone does not prove much. The path should show how the access network, premium Unicom segment, international network, and provider network connect.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Unicom user</span></span>
<span class="line"><span>-&gt; China Unicom access / AS4837</span></span>
<span class="line"><span>-&gt; China Unicom Premium / AS9929</span></span>
<span class="line"><span>-&gt; China Unicom Global / AS10099</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo / AS3258</span></span></code></pre>
<p>Riven Cloud peers with China Unicom Global through AS10099. China Unicom traffic from mainland China enters the premium AS9929 segment before reaching AS10099 and Riven Cloud.</p>
<h2 id="as9929-and-as10099-are-different-parts-of-the-route">AS9929 and AS10099 are different parts of the route<a href="#as9929-and-as10099-are-different-parts-of-the-route" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>AS9929 and AS10099 are not interchangeable.</p>
<p>AS9929 is the premium Unicom segment customers usually see on the mainland China side. It often appears after AS4837 access or regional hops. In the sample route below, traffic starts on AS4837, then enters AS9929 at hop 8 in the mainland China to Tokyo direction.</p>
<p>AS10099 is China Unicom Global’s international network. It is the AS Riven Cloud peers with for China Unicom Premium, and it handles the international side before traffic reaches Riven Cloud’s Tokyo network.</p>
<p>A useful CUP check looks for both parts. Seeing only one ASN is weaker evidence than seeing the full AS4837 -&gt; AS9929 -&gt; AS10099 -&gt; AS3258 pattern, with the reverse direction matching the same structure.</p>
<h2 id="the-riven-cloud-china-unicom-premium-path">The Riven Cloud China Unicom Premium path<a href="#the-riven-cloud-china-unicom-premium-path" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized China Unicom path for Riven Cloud Tokyo is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Unicom user</span></span>
<span class="line"><span>-&gt; China Unicom AS4837 access / regional network</span></span>
<span class="line"><span>-&gt; China Unicom Premium AS9929</span></span>
<span class="line"><span>-&gt; China Unicom Global AS10099</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo AS3258</span></span></code></pre>
<p>Each part has a role:</p>
<ul>
<li>AS4837 may appear because many users start from ordinary China Unicom access or regional networks.</li>
<li>AS9929 is the premium Unicom segment.</li>
<li>AS10099 is the China Unicom Global international side.</li>
<li>AS3258 is the Riven Cloud Tokyo test network.</li>
</ul>
<p>AS4837 near the access side does not mean the route failed to use premium Unicom routing. The next step is the useful part: whether the path moves into AS9929 and then AS10099.</p>
<h2 id="optimized-route-mtr-sample">Optimized route MTR sample<a href="#optimized-route-mtr-sample" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized MTR samples below were collected on June 29, 2026. The mainland China to Tokyo sample started at <code>2026-06-29T10:20:30+0000</code>. The Tokyo to mainland China sample started at <code>2026-06-29T10:20:36+0000</code>. Each MTR used 10 probes.</p>
<p>The visible AS path matched the expected China Unicom Premium structure in both directions.</p>


























<table><thead><tr><th>Direction</th><th>Visible premium path</th><th style="text-align:right">Final-hop avg RTT</th><th style="text-align:right">Best RTT</th><th style="text-align:right">Final-hop packet loss</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td>AS4837 -&gt; AS9929 -&gt; AS10099 -&gt; AS3258</td><td style="text-align:right">37.4 ms</td><td style="text-align:right">37.1 ms</td><td style="text-align:right">0.0%</td></tr><tr><td>Tokyo to mainland China</td><td>AS3258 -&gt; AS10099 -&gt; AS9929 -&gt; AS4837</td><td style="text-align:right">36.6 ms</td><td style="text-align:right">36.6 ms</td><td style="text-align:right">0.0%</td></tr></tbody></table>
<p>The mainland China to Tokyo MTR showed AS4837 on the access side, then AS9929, then AS10099, and the final Riven Cloud Tokyo endpoint on AS3258. The return MTR showed AS3258 first, then AS10099, then AS9929, and the final China Unicom endpoint on AS4837.</p>
<p>That is the important production signal: the route uses AS9929 and AS10099 in both directions, instead of leaving China Unicom through a generic international transit path.</p>
<h2 id="standard-softbank-transit-comparison">Standard SoftBank transit comparison<a href="#standard-softbank-transit-comparison" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The same June 29, 2026 comparison set also included a standard SoftBank transit baseline. SoftBank AS17676 is a normal international transit network. The point of the comparison is route matching for China Unicom users, not a claim that SoftBank is a bad network.</p>
<p>The baseline path was:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China Unicom user</span></span>
<span class="line"><span>-&gt; China Unicom AS4837</span></span>
<span class="line"><span>-&gt; SoftBank AS17676</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo AS3258</span></span></code></pre>
<p>Cleaned final-hop results from that baseline were:</p>


























<table><thead><tr><th>Direction</th><th>Standard transit path</th><th style="text-align:right">Final-hop avg RTT</th><th style="text-align:right">Best RTT</th><th style="text-align:right">Final-hop packet loss</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td>AS4837 -&gt; SoftBank/AS17676 -&gt; AS3258</td><td style="text-align:right">53.1 ms</td><td style="text-align:right">41.1 ms</td><td style="text-align:right">0.0%</td></tr><tr><td>Tokyo to mainland China</td><td>AS3258 -&gt; SoftBank/AS17676 -&gt; AS4837</td><td style="text-align:right">57.0 ms</td><td style="text-align:right">47.8 ms</td><td style="text-align:right">0.0%</td></tr></tbody></table>
<p>For this Unicom to Tokyo sample, the standard transit path had higher average RTT than the China Unicom Premium route in both directions.</p>
<h2 id="side-by-side-results">Side-by-side results<a href="#side-by-side-results" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The optimized path reduced average RTT in both directions.</p>


























<table><thead><tr><th>Direction</th><th style="text-align:right">Standard transit avg RTT</th><th style="text-align:right">CUP optimized avg RTT</th><th style="text-align:right">Reduction</th><th>Optimized path</th></tr></thead><tbody><tr><td>Mainland China to Tokyo</td><td style="text-align:right">53.1 ms</td><td style="text-align:right">37.4 ms</td><td style="text-align:right">15.7 ms lower / about 30% lower</td><td>AS9929 -&gt; AS10099</td></tr><tr><td>Tokyo to mainland China</td><td style="text-align:right">57.0 ms</td><td style="text-align:right">36.6 ms</td><td style="text-align:right">20.4 ms lower / about 36% lower</td><td>AS10099 -&gt; AS9929</td></tr></tbody></table>
<p>The RTT reduction is useful, but the cleaner route structure is the bigger signal. The optimized route used the intended China Unicom premium path rather than ordinary international transit.</p>
<p>For customers comparing AS9929 VPS or CUP VPS offers, this is the check that matters: AS4837 access, AS9929 premium segment, China Unicom Global AS10099, and the provider AS in both directions.</p>
<h2 id="why-this-matters-for-vps-users">Why this matters for VPS users<a href="#why-this-matters-for-vps-users" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Most customers do not care about AS paths until the network starts wasting their time.</p>
<p>For China Unicom users, a carrier-matched path can improve ordinary daily work:</p>
<ul>
<li>SSH sessions feel more responsive.</li>
<li>Websites load faster for users on China Unicom.</li>
<li>API calls from mainland China spend less time waiting on the network.</li>
<li>Control panels and remote desktop sessions feel less sticky.</li>
<li>Latency-sensitive applications get a cleaner path to Tokyo.</li>
<li>The service depends less on ordinary international transit during busy hours.</li>
</ul>
<p>The result still depends on the user’s local line and application behavior. Route optimization gives the traffic a better path. It does not make every last-mile network perfect.</p>
<h2 id="how-to-check-whether-a-route-is-really-china-unicom-premium">How to check whether a route is really China Unicom Premium<a href="#how-to-check-whether-a-route-is-really-china-unicom-premium" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>A good Unicom premium route often shows this pattern:</p>
<ul>
<li>AS4837 near the access side.</li>
<li>AS9929 as the premium Unicom segment.</li>
<li>AS10099 as the China Unicom Global international network.</li>
<li>The provider AS after AS10099.</li>
</ul>
<p>For Riven Cloud Tokyo, the expected optimized pattern is:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>China to Tokyo:</span></span>
<span class="line"><span>AS4837 -&gt; AS9929 -&gt; AS10099 -&gt; AS3258</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Tokyo to China:</span></span>
<span class="line"><span>AS3258 -&gt; AS10099 -&gt; AS9929 -&gt; AS4837</span></span></code></pre>
<p>Exact router IPs, hostnames, and city codes may change. The AS-level pattern is the part to check first.</p>
<h2 id="how-to-read-mtr-without-chasing-the-wrong-problem">How to read MTR without chasing the wrong problem<a href="#how-to-read-mtr-without-chasing-the-wrong-problem" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>MTR is useful, but intermediate hops can mislead.</p>
<p>Routers may rate-limit ICMP, deprioritize control-plane replies, or ignore probes while still forwarding customer traffic normally. A 100% non-response on an intermediate hop does not prove end-to-end packet loss when later hops and the final destination continue to respond.</p>
<p>The Tokyo to mainland China sample shows why this matters. Hop 5 reported 50.0% loss and a very high average latency, but later hops returned to normal and the final destination showed 36.6 ms average RTT with 0.0% packet loss. Treat that kind of isolated intermediate behavior as a diagnostic clue, not as final proof of customer traffic loss.</p>
<p>When checking CUP routes, focus on:</p>
<ul>
<li>Final-hop average RTT.</li>
<li>Final-hop packet loss.</li>
<li>Whether the path shows AS9929 and AS10099.</li>
<li>Whether the return direction also uses AS10099 and AS9929.</li>
<li>Whether the same loss pattern continues to the final destination.</li>
</ul>
<p>Short MTR samples are useful route evidence. They are not an SLA for every province, every hour, or every future routing change.</p>
<h2 id="what-china-unicom-premium-cannot-guarantee">What China Unicom Premium cannot guarantee<a href="#what-china-unicom-premium-cannot-guarantee" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Unicom Premium gives traffic a better path. It does not make every last-mile network perfect.</p>
<p>Performance can still depend on province, local broadband quality, office or residential network conditions, last-mile congestion, time of day, carrier routing changes, international cable incidents, application protocol, customer-side Wi-Fi, and customer router behavior.</p>
<p>CUP reduces dependence on ordinary international transit for China Unicom users. It cannot control every access network before AS4837, and it cannot fix an application that handles latency poorly.</p>
<p>Treat the route as one part of the deployment decision, alongside CPU, RAM, NVMe storage, monthly transfer, backup policy, and application design.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>For China Unicom users, Riven Cloud’s optimized Tokyo route is designed around the real China Unicom Premium path:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="text"><code><span class="line"><span>AS4837 access / regional network</span></span>
<span class="line"><span>-&gt; AS9929 premium segment</span></span>
<span class="line"><span>-&gt; China Unicom Global AS10099</span></span>
<span class="line"><span>-&gt; Riven Cloud Tokyo AS3258</span></span></code></pre>
<p>In the June 29, 2026 MTR samples, that path delivered 37.4 ms average RTT from mainland China to Tokyo and 36.6 ms average RTT from Tokyo back to mainland China, both with 0.0% final-hop packet loss.</p>
<p>The same-day standard SoftBank transit baseline averaged 53.1 ms from mainland China to Tokyo and 57.0 ms in the return direction. The lower RTT helps, but the route evidence is the real point: the optimized route shows the expected AS9929 and AS10099 path in both directions.</p>
<p>For a broader carrier view, read <a href="https://sa.net/blog/what-are-china-optimized-routes/" title="What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained">What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained</a>. For the other carrier-specific articles, see <a href="https://sa.net/blog/china-telecom-premium/" title="China Telecom premium routing">China Telecom premium routing</a> and <a href="https://sa.net/blog/china-mobile-premium/" title="China Mobile CMIN2 routing">China Mobile CMIN2 routing</a>. To test from Riven Cloud’s Tokyo location, use the <a href="https://tok-premium.lg.xtom.com/" title="Tokyo Looking Glass" target="_blank" rel="noopener noreferrer">Tokyo Looking Glass</a>.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="China Unicom" term="China Unicom"/>
        <category label="China Unicom Premium" term="China Unicom Premium"/>
        <category label="CUP" term="CUP"/>
        <category label="AS9929" term="AS9929"/>
        <category label="AS10099" term="AS10099"/>
        <category label="China-optimized VPS" term="China-optimized VPS"/>
        <category label="Routing" term="Routing"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[What are China-optimized routes? CTGNet/CN2 GIA, CUP, and CMIN2 explained]]></title>
        <id>https://sa.net/blog/what-are-china-optimized-routes/</id>
        <link href="https://sa.net/blog/what-are-china-optimized-routes/"/>
        <updated>2026-06-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn what three-network optimization means for mainland China users and how Riven Cloud uses CTGNet/CN2 GIA, China Unicom Premium, and CMIN2 to improve VPS connectivity.]]></summary>
        <content type="html"><![CDATA[<p>Many VPS providers use “China optimized” to mean any route that reaches mainland China reasonably well. For Tokyo, that is too vague.</p>
<p>A China Telecom home connection, a China Unicom office line, and a China Mobile phone can take different international paths to the same VPS. A route that looks fine for one carrier may be the wrong path for another.</p>
<p>In the mainland China VPS market, “three-network optimization” means treating the three major carrier networks separately:</p>
<ul>
<li>China Telecom</li>
<li>China Unicom</li>
<li>China Mobile</li>
</ul>
<p>Riven Cloud’s optimized Tokyo routing is built around that model. China Telecom traffic uses the CN2/AS4809 domestic premium path and reaches Riven Cloud through CTGNet/AS23764. China Unicom traffic uses AS9929 on the mainland China side and reaches Riven Cloud through China Unicom Global AS10099. China Mobile traffic uses AS9808 domestically and reaches Riven Cloud through CMIN2/AS58807.</p>
<p>Lower latency is part of the story, but carrier matching matters just as much. A good China route should avoid pushing all three carriers through the same ordinary transit path and hoping the result holds during peak hours.</p>
<p>The comparison data below comes from cleaned MTR samples collected on June 29, 2026. Exact customer endpoints, VPS addresses, router IPs, private IPs, and hostnames have been redacted. The article keeps the parts that matter for route analysis: carrier labels, ASNs, direction, final-hop average RTT, final-hop packet loss, and visible AS-level paths.</p>
<h2 id="what-are-the-three-networks-in-china">What are the three networks in China?<a href="#what-are-the-three-networks-in-china" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Telecom, China Unicom, and China Mobile are the three carrier networks most VPS buyers care about when serving users in mainland China.</p>
<p>That matters because a “China route” is not a single path. A user in Shanghai on China Telecom, a developer in Beijing on China Unicom, and a phone on China Mobile can take very different routes to the same VPS in Tokyo. A path that works well for one carrier may be ordinary, indirect, or congested for another.</p>
<p>A China-optimized route needs to be carrier-specific. One decent international transit provider is not the same thing as three-network optimization.</p>
<h2 id="why-ordinary-international-transit-is-not-enough">Why ordinary international transit is not enough<a href="#why-ordinary-international-transit-is-not-enough" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Standard global transit can be good for general international traffic. For users in North America, Europe, Japan, Singapore, and many other markets, a well-connected transit blend may be perfectly reasonable.</p>
<p>Mainland China traffic is different. The route depends heavily on carrier-specific international gateways, domestic backbone policy, handoff points, and the relationship between the overseas network and each Chinese carrier.</p>
<p>Ordinary transit may enter China through a less ideal carrier path. It may take a detour through another region. It may work acceptably at one time of day and become inconsistent during evening peak. It may also be asymmetric: the route from China to Tokyo can look different from the route from Tokyo back to China.</p>
<p>Bandwidth is only one part of network quality. For many applications, latency, packet loss, jitter, and route consistency matter more than a large port number on a plan page. A 1 Gbps port does not help much if packets reach the wrong international gateway or bounce through a congested carrier path.</p>
<h2 id="china-telecom-ctgnet-and-cn2-gia">China Telecom: CTGNet and CN2 GIA<a href="#china-telecom-ctgnet-and-cn2-gia" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China Telecom is the easiest one to mislabel.</p>
<p>CTGNet is China Telecom’s newer premium international network, associated with AS23764. CN2, commonly discussed in the VPS market as CN2 GIA, is tied to the premium China Telecom backbone segment associated with AS4809. These are related in the customer experience, but they are not the same phrase with two names.</p>
<p>Riven Cloud’s path should not be described as “CTGNet equals CN2 GIA.” The domestic premium segment and the international delivery path are different parts of the route. In this setup, China Telecom traffic uses the CN2/AS4809 domestic premium segment and reaches Riven Cloud through CTGNet/AS23764.</p>
<p>Riven Cloud peers with China Telecom through CTGNet AS23764. On the mainland China side, traffic can traverse the CN2/59.43 segment associated with AS4809 before it reaches the CTGNet AS23764 edge and then Riven Cloud’s Tokyo network.</p>
<p>As of June 29, 2026, PeeringDB lists <a href="https://www.peeringdb.com/net/17755" title="CTGNet as AS23764" target="_blank" rel="noopener noreferrer">CTGNet as AS23764</a>. That public record matches the peer-facing ASN discussed here.</p>
<p>In our sample MTR tests, the optimized China Telecom route showed an average final-hop RTT of 36.3 ms from a China Telecom access sample to the Riven Cloud Tokyo optimized test node, with 36.1 ms best RTT and 0.0% final-hop packet loss. In the reverse direction, from Tokyo back to the China Telecom access sample, the optimized route showed 41.6 ms average final-hop RTT, 41.6 ms best RTT, and 0.0% final-hop packet loss.</p>
<p>The ordinary SoftBank transit baseline for the same carrier sample used AS4134 -&gt; SoftBank AS17676 -&gt; Riven Cloud AS3258 in the China-to-Tokyo direction, and Riven Cloud AS3258 -&gt; SoftBank AS17676 -&gt; AS4134 in the return direction. The final hop averaged 78.1 ms with 30.0% packet loss from China to Tokyo, and 74.1 ms with 10.0% packet loss from Tokyo back to China.</p>



































<table><thead><tr><th>Measurement</th><th>Ordinary SoftBank transit</th><th>CTGNet/CN2 optimized route</th></tr></thead><tbody><tr><td>China to Tokyo AS path</td><td>AS4134 -&gt; SoftBank AS17676 -&gt; Riven Cloud AS3258</td><td>AS4134 access -&gt; CN2/AS4809 -&gt; CTGNet/AS23764 -&gt; Riven Cloud AS3258</td></tr><tr><td>China to Tokyo final hop</td><td>78.1 ms avg / 69.6 ms best / 30.0% loss</td><td>36.3 ms avg / 36.1 ms best / 0.0% loss</td></tr><tr><td>Tokyo to China AS path</td><td>Riven Cloud AS3258 -&gt; SoftBank AS17676 -&gt; AS4134</td><td>Riven Cloud AS3258 -&gt; CTGNet/AS23764 -&gt; CN2/AS4809 -&gt; AS4134</td></tr><tr><td>Tokyo to China final hop</td><td>74.1 ms avg / 63.1 ms best / 10.0% loss</td><td>41.6 ms avg / 41.6 ms best / 0.0% loss</td></tr><tr><td>Result in this sample</td><td>Standard transit was 41.8 ms slower China to Tokyo and 32.5 ms slower Tokyo to China</td><td>The optimized path was about 54% lower RTT China to Tokyo and 44% lower RTT Tokyo to China</td></tr></tbody></table>
<p>This does not mean every China Telecom user will always see those exact numbers. It does show the route difference clearly: CN2/AS4809 and CTGNet/AS23764 on the optimized path, compared with ordinary SoftBank transit on the baseline path.</p>
<p>For the carrier-specific breakdown, read <a href="https://sa.net/blog/china-telecom-premium/" title="What is CTGNet / CN2 GIA? China Telecom premium routing explained">What is CTGNet / CN2 GIA? China Telecom premium routing explained</a>.</p>
<h2 id="china-unicom-cup-and-china-unicom-premium">China Unicom: CUP and China Unicom Premium<a href="#china-unicom-cup-and-china-unicom-premium" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CUP means China Unicom Premium.</p>
<p>For Riven Cloud’s optimized China Unicom path, the mainland China side uses AS9929 as the premium backbone and international exit segment. Riven Cloud peers with China Unicom Global through AS10099. AS4837 may still appear before traffic enters AS9929, because AS4837 is commonly seen as an ordinary China Unicom regional or access network.</p>
<p>The accurate shorthand is:</p>
<p>China Unicom traffic uses AS9929 on the mainland China side and reaches Riven Cloud through China Unicom Global AS10099.</p>
<p>As of June 29, 2026, PeeringDB lists <a href="https://www.peeringdb.com/net/7268" title="China Unicom Global as AS10099" target="_blank" rel="noopener noreferrer">China Unicom Global as AS10099</a>. In the optimized sample, the visible AS path from mainland China to Tokyo was AS4837 -&gt; AS9929 -&gt; AS10099 -&gt; Riven Cloud AS3258. The return direction showed Riven Cloud AS3258 -&gt; AS10099 -&gt; AS9929 -&gt; AS4837.</p>
<p>The useful part is where AS9929 appears. AS4837 may still show up near the access side, but the cross-border segment moves onto the premium Unicom path through AS9929 and AS10099.</p>
<p>In our sample, the optimized China Unicom route averaged 37.4 ms from China to Tokyo, with 37.1 ms best RTT and 0.0% final-hop packet loss. The return direction averaged 36.6 ms, with 36.6 ms best RTT and 0.0% final-hop packet loss.</p>
<p>The ordinary SoftBank transit baseline used AS4837 -&gt; SoftBank AS17676 -&gt; Riven Cloud AS3258 from China to Tokyo, and Riven Cloud AS3258 -&gt; SoftBank AS17676 -&gt; AS4837 in the return direction. It averaged 53.1 ms from China to Tokyo and 57.0 ms from Tokyo back to China, both with 0.0% final-hop packet loss.</p>



































<table><thead><tr><th>Measurement</th><th>Ordinary SoftBank transit</th><th>CUP/AS9929 optimized route</th></tr></thead><tbody><tr><td>China to Tokyo AS path</td><td>AS4837 -&gt; SoftBank AS17676 -&gt; Riven Cloud AS3258</td><td>AS4837 -&gt; AS9929 -&gt; China Unicom Global AS10099 -&gt; Riven Cloud AS3258</td></tr><tr><td>China to Tokyo final hop</td><td>53.1 ms avg / 41.1 ms best / 0.0% loss</td><td>37.4 ms avg / 37.1 ms best / 0.0% loss</td></tr><tr><td>Tokyo to China AS path</td><td>Riven Cloud AS3258 -&gt; SoftBank AS17676 -&gt; AS4837</td><td>Riven Cloud AS3258 -&gt; China Unicom Global AS10099 -&gt; AS9929 -&gt; AS4837</td></tr><tr><td>Tokyo to China final hop</td><td>57.0 ms avg / 47.8 ms best / 0.0% loss</td><td>36.6 ms avg / 36.6 ms best / 0.0% loss</td></tr><tr><td>Result in this sample</td><td>Standard transit was 15.7 ms slower China to Tokyo and 20.4 ms slower Tokyo to China</td><td>The optimized path was about 30% lower RTT China to Tokyo and 36% lower RTT Tokyo to China</td></tr></tbody></table>
<p>For the carrier-specific breakdown, read <a href="https://sa.net/blog/china-unicom-premium/" title="What is China Unicom Premium? CUP, AS9929, and AS10099 explained">What is China Unicom Premium? CUP, AS9929, and AS10099 explained</a>.</p>
<h2 id="china-mobile-cmin2">China Mobile: CMIN2<a href="#china-mobile-cmin2" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>CMIN2 means China Mobile International N2. It is the important path to look for when evaluating optimized China Mobile routing.</p>
<p>Riven Cloud peers with CMIN2 through AS58807. Mainland China traffic uses AS9808 domestically before reaching AS58807. In contrast, ordinary China Mobile international routes may use older CMI paths such as AS58453, often with additional transit such as SoftBank AS17676 in the baseline route.</p>
<p>The accurate shorthand is:</p>
<p>China Mobile traffic uses AS9808 domestically and reaches Riven Cloud through CMIN2/AS58807.</p>
<p>As of June 29, 2026, PeeringDB lists <a href="https://www.peeringdb.com/net/22581" title="China Mobile International - NII as AS58807" target="_blank" rel="noopener noreferrer">China Mobile International - NII as AS58807</a>, with CMIN2 as its listed aka.</p>
<p>In our optimized sample, the visible AS path from mainland China to Tokyo was China Mobile regional/access network -&gt; AS9808 -&gt; CMIN2 AS58807 -&gt; Riven Cloud AS3258. The return direction showed Riven Cloud AS3258 -&gt; CMIN2 AS58807 -&gt; AS9808 -&gt; China Mobile regional/access network.</p>
<p>The optimized route averaged 40.0 ms from China to Tokyo, with 39.8 ms best RTT and 0.0% final-hop packet loss. The return direction averaged 44.7 ms, with 44.6 ms best RTT and 0.0% final-hop packet loss.</p>
<p>The ordinary SoftBank transit baseline used China Mobile regional/access network -&gt; AS9808 -&gt; ordinary CMI AS58453 -&gt; SoftBank AS17676 -&gt; Riven Cloud AS3258 from China to Tokyo, and the same general chain in reverse from Tokyo back to China. It averaged 72.2 ms from China to Tokyo and 70.0 ms from Tokyo back to China, both with 0.0% final-hop packet loss.</p>



































<table><thead><tr><th>Measurement</th><th>Ordinary SoftBank transit</th><th>CMIN2 optimized route</th></tr></thead><tbody><tr><td>China to Tokyo AS path</td><td>China Mobile regional/access -&gt; AS9808 -&gt; ordinary CMI AS58453 -&gt; SoftBank AS17676 -&gt; Riven Cloud AS3258</td><td>China Mobile regional/access -&gt; AS9808 -&gt; CMIN2 AS58807 -&gt; Riven Cloud AS3258</td></tr><tr><td>China to Tokyo final hop</td><td>72.2 ms avg / 72.0 ms best / 0.0% loss</td><td>40.0 ms avg / 39.8 ms best / 0.0% loss</td></tr><tr><td>Tokyo to China AS path</td><td>Riven Cloud AS3258 -&gt; SoftBank AS17676 -&gt; ordinary CMI AS58453 -&gt; AS9808 -&gt; China Mobile regional/access</td><td>Riven Cloud AS3258 -&gt; CMIN2 AS58807 -&gt; AS9808 -&gt; China Mobile regional/access</td></tr><tr><td>Tokyo to China final hop</td><td>70.0 ms avg / 69.9 ms best / 0.0% loss</td><td>44.7 ms avg / 44.6 ms best / 0.0% loss</td></tr><tr><td>Result in this sample</td><td>Standard transit was 32.2 ms slower China to Tokyo and 25.3 ms slower Tokyo to China</td><td>The optimized path was about 45% lower RTT China to Tokyo and 36% lower RTT Tokyo to China</td></tr></tbody></table>
<p>For China Mobile customers, AS58807 is the signal to look for. The optimized sample uses CMIN2 instead of the ordinary AS58453/SoftBank transit path.</p>
<p>For the carrier-specific breakdown, read <a href="https://sa.net/blog/china-mobile-premium/" title="What is CMIN2? China Mobile International N2 and AS58807 explained">What is CMIN2? China Mobile International N2 and AS58807 explained</a>.</p>
<h2 id="how-to-read-these-mtr-samples">How to read these MTR samples<a href="#how-to-read-these-mtr-samples" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>The carrier sections above use cleaned sample MTR results collected on June 29, 2026. We publish carrier names, AS-level paths, direction, final-hop average RTT, and final-hop packet loss. We do not publish customer IP addresses, VPS IP addresses, router IPs, private IPs, hostnames, or full raw MTR output.</p>
<p>Treat these as point-in-time samples, not universal guarantees. The useful checks are simple: final-hop RTT, final-hop packet loss, visible AS path, and whether the route lands on the expected carrier network. In these samples, the optimized route had lower average final-hop RTT in both directions for all three carriers. The optimized samples also showed 0.0% final-hop packet loss, while the ordinary China Telecom baseline showed final-hop loss in this short sample.</p>
<p>Intermediate MTR packet loss, including 100% non-response on an intermediate hop, does not automatically mean real end-to-end packet loss. Many routers rate-limit or ignore ICMP while still forwarding customer traffic normally.</p>
<p>Use the ordinary SoftBank examples as a standard international transit baseline. SoftBank AS17676 is a major network. For this Tokyo-to-mainland-China use case, the carrier-specific premium paths fit better than a general transit path.</p>
<h2 id="what-customers-actually-feel">What customers actually feel<a href="#what-customers-actually-feel" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>Most customers do not buy a route table. They buy a VPS because they want a website, API, control panel, game server, proxy service, development box, or internal tool to feel usable from mainland China.</p>
<p>The difference usually shows up in boring places: SSH stops feeling sticky, admin panels load without the first click hanging, and API calls from mainland China spend less time waiting on the network. It will not make every app fast, but it removes one common source of delay.</p>
<p>Peak-hour consistency is often the bigger win. A route that looks acceptable in the afternoon can become a problem in the evening if it depends on a congested international path. Matching China Telecom, China Unicom, and China Mobile to their own premium paths reduces that risk.</p>
<p>It does not remove every risk or guarantee the same latency for every province, office, mobile network, or residential line. Packet loss can still happen. The VPS starts from a better network position.</p>
<h2 id="what-china-optimized-routing-cannot-guarantee">What China-optimized routing cannot guarantee<a href="#what-china-optimized-routing-cannot-guarantee" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China-optimized routing improves path selection. It is not a physics exemption or a replacement for operational monitoring.</p>
<p>Performance can still depend on province, local ISP, last-mile quality, time of day, cross-border congestion, cable incidents, carrier routing changes, and the application itself. A user on weak Wi-Fi behind an overloaded local access network can still have a poor experience even if the international route is excellent.</p>
<p>MTR is a useful diagnostic tool, but it is not a full SLA. It shows a path sample at a point in time. That sample is valuable when it confirms the expected AS path and final-hop behavior, but it should not be treated as absolute proof that every future flow will behave identically.</p>
<p>The practical goal is better route selection: China Telecom through CN2/AS4809 and CTGNet/AS23764, China Unicom through AS9929 and China Unicom Global AS10099, and China Mobile through AS9808 and CMIN2/AS58807.</p>
<h2 id="choosing-a-tokyo-vps-for-mainland-china-users">Choosing a Tokyo VPS for mainland China users<a href="#choosing-a-tokyo-vps-for-mainland-china-users" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>For a normal VPS buyer, CPU, RAM, NVMe storage, and transfer quota still matter. A busy application needs enough compute and disk performance. A high-traffic service needs a plan with enough monthly transfer. A production system needs backups and sensible operations.</p>
<p>For mainland China users, the network path can matter just as much.</p>
<p>A generic Japan VPS may be physically close to China, but physical distance is only one part of the route. The carrier path decides whether traffic enters the right Chinese backbone, whether the return direction is sensible, and whether the route remains stable when ordinary international transit gets busy.</p>
<p>Riven Cloud’s China-optimized Tokyo VPS routing is designed for customers who need that carrier-aware path: CTGNet/CN2 GIA for China Telecom, CUP for China Unicom, and CMIN2 for China Mobile.</p>
<h2 id="conclusion">Conclusion<a href="#conclusion" class="heading-anchor" aria-hidden="true" tabindex="-1" data-hash="#"></a></h2>
<p>China-optimized routing means matching each major mainland China carrier with its own premium path.</p>
<p>For Riven Cloud’s optimized Tokyo route, that means China Telecom traffic uses CN2/AS4809 domestically and CTGNet/AS23764 internationally, China Unicom traffic uses AS9929 and China Unicom Global AS10099, and China Mobile traffic uses AS9808 and CMIN2/AS58807.</p>
<p>That is what “three-network optimization” should mean in practice. It is not a slogan and it is not one generic overseas route. It is separate carrier engineering for China Telecom, China Unicom, and China Mobile.</p>
<p>If your users are in mainland China, the route can matter as much as CPU, RAM, and storage. Riven Cloud’s Tokyo route is built around that reality: China Telecom, China Unicom, and China Mobile each need their own path.</p>
<p>If you need a VPS with three-network optimized routing, you can order one at <a href="https://sa.net/" title="sa.net" target="_blank" rel="noopener noreferrer">sa.net</a>.</p>]]></content>
        <author>
            <name>Riven Cloud OÜ</name>
            <email>sales@riven.cloud</email>
            <uri>https://sa.net/</uri>
        </author>
        <category label="China-optimized VPS" term="China-optimized VPS"/>
        <category label="CTGNet" term="CTGNet"/>
        <category label="CN2 GIA" term="CN2 GIA"/>
        <category label="China Unicom Premium" term="China Unicom Premium"/>
        <category label="CUP" term="CUP"/>
        <category label="CMIN2" term="CMIN2"/>
        <category label="BGP" term="BGP"/>
        <category label="China Telecom" term="China Telecom"/>
        <category label="China Unicom" term="China Unicom"/>
        <category label="China Mobile" term="China Mobile"/>
    </entry>
</feed>