Building a Custom CDN Edge Node in Singapore Using Varnish Cache and Nginx on Budget VPS
Introduction: The Case for a Custom CDN Edge Node
In today's digital landscape, website speed is no longer just a luxury—it is a critical business metric. For enterprises and developers targeting audiences across Southeast Asia, hosting infrastructure in Singapore is the gold standard due to its world-class connectivity. However, relying solely on centralized cloud hosting or expensive commercial Content Delivery Networks (CDNs) can quickly erode your infrastructure budget. This guide provides a sophisticated alternative: building your own personal CDN Edge Node using a budget-friendly Singapore-based Virtual Private Server (VPS), powered by the combined efficiency of Varnish Cache and Nginx.
By deploying this architecture, you gain absolute control over your caching policies, eliminate unpredictable bandwidth costs, and dramatically reduce Time to First Byte (TTFB) for your end-users. Let us explore how to engineer this high-performance solution from scratch.
---The Architecture: Why Varnish Cache and Nginx?
To understand the efficacy of this setup, it is vital to analyze the distinct roles that Varnish Cache and Nginx play within our edge node pipeline:
- Varnish Cache (The Speed Daemon): Sitting at the very front of your edge server, Varnish acts as a reverse proxy HTTP accelerator. It stores requested web assets directly in memory (RAM). When a user requests a cached page, Varnish serves it instantaneously, bypassing heavy backend processing entirely.
- Nginx (The Reliable Gateway & TLS Terminator): While Varnish excels at caching, it does not natively support HTTPS/TLS traffic in its open-source version. This is where Nginx becomes indispensable. Nginx acts as a TLS terminator, handling secure SSL connections from users, decrypting the traffic, passing it to Varnish, and re-encrypting the response. It also handles fallback logic and advanced logging.
By combining Nginx's robust security handling with Varnish's unparalleled memory-caching capabilities, we create a enterprise-grade edge node capable of handling thousands of concurrent requests even on a single-core, low-RAM budget VPS.---
Prerequisites and Environment Setup
Before proceeding with the technical deployment, ensure you have the following prerequisites in place:
- A budget VPS located in a Singapore data center (providers like Linode, DigitalOcean, Vultr, or local Asian providers often offer plans starting at $4 to $5 per month).
- A clean installation of Ubuntu 22.04 LTS or 24.04 LTS on the VPS.
- Root or
sudoaccess to the server. - A domain name with DNS controls pointed toward your edge server's public IP address.
- An upstream "Origin Server" where your actual website or application is currently hosted.
Step 1: Installing and Configuring Nginx for TLS Termination
Our first objective is to configure Nginx to listen on the standard web ports (80 and 443) to accept incoming user requests. It will handle the SSL handshake and route traffic internally to Varnish.
1.1 Installation
Update your system repositories and install Nginx alongside Certbot for automated Let's Encrypt SSL certificates:
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx -y1.2 Configuring the Nginx Frontend
Create a new server block configuration file for your domain (e.g., /etc/nginx/sites-available/cdn-edge). This configuration will instruct Nginx to forward decrypted traffic to Varnish, which will run internally on port 8080.
server {
listen 80;
listen [::]:80;
server_name cdn.yourdomain.com;
# Redirect all HTTP traffic to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cdn.yourdomain.com;
# SSL Configuration placeholder (Certbot will populate this)
ssl_certificate /etc/letsencrypt/live/[cdn.yourdomain.com/fullchain.pem](https://cdn.yourdomain.com/fullchain.pem);
ssl_certificate_key /etc/letsencrypt/live/[cdn.yourdomain.com/privkey.pem](https://cdn.yourdomain.com/privkey.pem);
location / {
proxy_pass [http://127.0.0.1:8080](http://127.0.0.1:8080);
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Enable the site configuration by creating a symbolic link and reload Nginx:
sudo ln -s /etc/nginx/sites-available/cdn-edge /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx---Step 2: Installing and Optimizing Varnish Cache
With Nginx prepared to forward traffic to port 8080, we now install Varnish Cache and configure it to listen on that exact port, while fetching data from our remote Origin Server when a cache miss occurs.
2.1 Installation
Install Varnish using the official package manager:
sudo apt install varnish -y2.2 Adjusting the Varnish Listening Port
By default, Varnish listens on port 6081. We need to alter this to port 8080. Edit the systemd service override file:
sudo systemctl edit varnishIn the editor, append the following lines to modify the execution parameters, ensuring we allocate a specific amount of memory suitable for a cheap VPS (e.g., 256MB of RAM allocation leaves plenty of room for system processes on a 1GB VPS):
[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -a :8080 -a localhost:8443,PROXY -f /etc/varnish/default.vcl -s malloc,256m---Step 3: Engineering the Varnish Configuration File (VCL)
The true intelligence of your CDN edge node resides within the Varnish Configuration Language (VCL) file located at /etc/varnish/default.vcl. Here, we define our origin backend and structure caching logic.
Replace the contents of the file with the following professional-grade production blueprint:
vcl 4.1;
backend default {
.host = "origin-server-ip-or-domain.com";
.port = "80";
.connect_timeout = 5s;
.first_byte_timeout = 10s;
.between_bytes_timeout = 2s;
}
sub vcl_recv {
# Forward the real client IP to the backend
if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
# Only cache GET and HEAD requests
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Strip tracking cookies or analytics cookies to increase hit rate
if (req.http.Cookie) {
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|utm_[a-z]+|_ga|_gid)=[^;]*", "");
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
}
return (hash);
}
sub vcl_backend_response {
# Cache static assets for 1 day automatically if backend doesn't object
if (beresp.http.content-type ~ "text/css" || beresp.http.content-type ~ "application/javascript" || beresp.http.content-type ~ "image/") {
set beresp.ttl = 1d;
unset beresp.http.Set-Cookie;
}
# Allow browser caching via Cache-Control headers
if (beresp.status == 200) {
set beresp.http.Cache-Control = "public, max-age=86400";
}
}
sub vcl_deliver {
# Add a debugging header to verify CDN status
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT from Singapore-Edge";
set resp.http.X-Cache-Hits = obj.hits;
} else {
set resp.http.X-Cache = "MISS from Singapore-Edge";
}
}Apply the changes by reloading the systemd daemon and restarting Varnish:
sudo systemctl daemon-reload
sudo systemctl restart varnish---Step 4: Verification, Testing, and Analytics
To ensure your custom CDN edge node is successfully operational, execute a curl command from an external machine to inspect the HTTP headers:
curl -I [https://cdn.yourdomain.com/assets/style.css](https://cdn.yourdomain.com/assets/style.css)On the initial execution, you should notice the custom debug header displaying X-Cache: MISS from Singapore-Edge. Upon executing the command a second time, the header should instantly transform to X-Cache: HIT from Singapore-Edge, verifying that the asset is being instantly served directly from the Singapore VPS memory space.
For real-time monitoring of your traffic metrics and cache hit ratios, utilize the built-in command-line utility:
varnishstat---Conclusion and Next Steps
By leveraging an affordable Singapore VPS alongside the precision of Nginx and Varnish Cache, you have successfully deployed a functional, lightning-fast custom CDN Edge Node. This implementation drastically reduces latency for users throughout Southeast Asia while relieving your origin server of heavy compute burdens.
As you expand your architecture, consider implementing a GeoDNS routing mechanism to dynamically send users to multiple edge nodes globally, building a truly resilient, self-hosted content delivery network tailored perfectly to your business requirements.
