LanCache on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and use of LanCache on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. LanCache is a self-hosted caching server for large game and content downloads. It transparently caches HTTP downloads from an allow-listed set of game-content CDNs — Steam, Epic Games, Riot, Blizzard/Battle.net, Origin/EA, GOG, Windows Update and more — so a file downloaded once is served from your local network at LAN speed to every other machine, instead of being pulled over the internet again and again.
LanCache has two parts, and this image ships both as the official, pinned upstream containers running under Docker:
- The cache —
lancachenet/monolithic, an nginx transparent cache on ports 80 (HTTP) and 443 (HTTPS SNI passthrough). - The DNS —
lancachenet/lancache-dns, which answers the cached CDN domains with the cache's own IP so clients are steered to the cache automatically. This image runs it in a hardened, closed configuration (see below).
There is no login and no credential of any kind — a cache and DNS service has no user interface. Because the appliance is reachable on the network by design, cloudimg closes the two ways an internet-facing cache could be abused, and proves both on every build before the image is captured:
- It is not an open DNS resolver. The DNS answers only the allow-listed CDN domains (authoritatively, with this VM's IP) and returns
REFUSEDfor every other name — no recursion and no forwarding, so it cannot be used for DNS amplification. - It is not an open proxy or TLS relay. The cache proxies only allow-listed CDN hosts on port 80, and relays only allow-listed SNIs on port 443. An arbitrary HTTP
Hostis refused and an arbitrary TLSSNIis dropped.
At first boot, lancache-firstboot.service resolves this VM's own public IP, writes the per-VM DNS zone so the cached domains resolve to it, and starts both containers. Cache data lives on the OS disk under /var/lib/lancache.
What is included:
-
The official
lancachenet/monolithiccache andlancachenet/lancache-dnsDNS, pulled and pinned by SHA-256 digest (never:latest) and verified against the pin at build time -
lancache-firstboot.service, a systemd oneshot that resolves the per-VM public IP, renders the DNS zone and starts both containers on the first customer boot -
A closed DNS: authoritative-only zones for the cached CDN domains,
recursion no, so arbitrary names areREFUSED -
A hardened cache: an nginx allow-list guard on port 80 and an SNI allow-list on port 443, so only the cached CDNs are served
-
The allow-list of game-content CDN domains, extracted from the official lancache-dns image (the
uklans/cache-domainsdata) -
Cache storage on a 64 GiB OS disk under
/var/lib/lancache, expandable for larger caches -
Ubuntu 24.04 LTS base with latest security patches applied at build time and unattended security updates enabled
-
Azure Linux Agent for seamless cloud integration and SSH key injection
-
24/7 cloudimg support with a guaranteed 24 hour response SLA
Prerequisites
-
An active Azure subscription
-
A subscription to the LanCache on Ubuntu 24.04 listing on Azure Marketplace
-
An SSH public key for VM authentication
-
A virtual network and subnet in the target region, reachable by the client machines you want to serve
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM). LanCache is very light on CPU and memory — the two containers together use well under 100 MB of RAM at idle. The resource that matters for a cache is disk: the more storage you give it, the more content it can hold. For a large LAN party or a busy venue, move the cache data to a larger disk (see the last section).
Network security group (NSG) ports. Open these to the client networks that will use the cache:
- UDP and TCP 53 — DNS (clients point their resolver here)
- TCP 80 — HTTP cache
- TCP 443 — HTTPS (SNI passthrough) cache
- TCP 22 — SSH, from your management IP range only
Scope 53/80/443 to your LAN or client source ranges. The appliance is hardened against open-resolver and open-proxy abuse, but there is no reason to expose a download cache to the whole internet.
Step 1: Deploy from the Azure Portal
Navigate to Marketplace in the Azure Portal, search for LanCache, select the cloudimg publisher entry, and click Create.
On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range, and inbound UDP+TCP 53, TCP 80 and TCP 443 from your client source ranges. Click Review + create, wait for validation, then Create. Deployment takes around two minutes.
Step 2: Deploy from the Azure CLI
RG="lancache-prod"
LOCATION="eastus"
VM_NAME="lancache-01"
ADMIN_USER="azureuser"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/lancache-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" \
--name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username "$ADMIN_USER" \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
# Open the LanCache ports (scope the source ranges to your client networks)
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 53 --priority 1010
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1020
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 443 --priority 1030
SSH in as your admin user once the VM is running:
ssh azureuser@<vm-ip>
Step 3: Confirm both containers are running
First boot resolves this VM's public IP and starts the cache and the DNS. Confirm the two containers are up, the DNS/HTTP/HTTPS ports are listening, and the cache heartbeat is healthy.
sudo docker ps --format '{{.Names}} {{.Status}}'
systemctl is-active docker lancache-firstboot
sudo ss -lntup | grep -E ':53 |:80 |:443 '
curl -s -o /dev/null -w 'heartbeat -> HTTP %{http_code}\n' http://127.0.0.1/lancache-heartbeat
You should see lancache-monolithic and lancache-dns both Up, docker and lancache-firstboot both active, sockets listening on 53, 80 and 443, and the heartbeat returning HTTP 204.

Step 4: Confirm the DNS is closed to abuse
The DNS answers the cached CDN domains with this VM's IP, and refuses everything else. The commands below use the first domain from the shipped allow-list; the appliance serves well over a hundred CDN domains.
CACHE_IP=$(sudo grep '^LANCACHE_IP=' /root/lancache-credentials.txt | cut -d= -f2-)
CDN=$(head -1 /var/lib/lancache/dns/cache-domains.txt)
echo "cache IP = $CACHE_IP sample cached domain = $CDN"
# A cached CDN domain (and any subdomain of it) resolves to this cache
dig +short @127.0.0.1 "$CDN" A
dig +short @127.0.0.1 "sub.$CDN" A
# An arbitrary domain is REFUSED - this is NOT an open resolver
dig @127.0.0.1 example.com A | grep -E 'status:'
The two dig +short lookups return the cache IP; the example.com lookup returns status: REFUSED with no answer. That is the appliance refusing to recurse for anything outside its allow-list.

Step 5: Confirm the cache is closed to abuse
The cache serves the allow-listed CDNs only. An arbitrary HTTP Host is refused (not proxied), and an arbitrary TLS SNI is dropped (not relayed).
CDN=$(head -1 /var/lib/lancache/dns/cache-domains.txt)
# A request for a cached CDN domain is handled by the lancache cache (X-LanCache header)
curl -s -D - -o /dev/null -H "Host: $CDN" http://127.0.0.1/lancache-heartbeat | grep -iE 'HTTP/|X-LanCache'
# An arbitrary HTTP Host is refused - the connection is closed, so curl exits non-zero
curl -s -o /dev/null -H 'Host: example.com' http://127.0.0.1/ ; echo "arbitrary HTTP Host -> curl exit $? (non-zero / refused = not an open proxy)"
# An arbitrary TLS SNI relays no upstream certificate
CERTS=$(timeout 8 openssl s_client -connect 127.0.0.1:443 -servername example.com </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE')
echo "arbitrary TLS SNI -> certificates relayed: $CERTS (0 = not an open TLS relay)"

Step 6: Point your network at the cache
To start caching, point your clients' DNS at this VM. The appliance answers only the cached CDN domains (with its own IP) and refuses everything else, so it is not a general-purpose resolver. Two common ways to use it:
- Conditional forwarding (recommended): on your existing DNS server or router, forward only the lancache CDN domains to this VM, and keep your normal resolver for everything else. This keeps general browsing working through your usual DNS.
- Per-client: set the DNS server on the machines you want to cache to this VM's IP, and add a secondary DNS for general name resolution.
The per-VM appliance info file records this VM's IP and how to use it. The container images are pinned by digest.
sudo cat /root/lancache-credentials.txt
sudo docker images --digests --format '{{.Repository}} {{.Digest}}' | grep lancachenet
df -h /

Once clients resolve a cached CDN through this VM, their first download of a given file fills the cache (a MISS); every subsequent machine that downloads the same file gets it from the cache at LAN speed (a HIT). No client-side software is needed — the caching is transparent.
Step 7: Sizing and expanding the cache
Cache data lives under /var/lib/lancache on the OS disk, which ships at 64 GiB. A game or content cache can grow large, so for anything beyond casual use, give it more storage:
- Resize the OS disk in the Azure Portal (VM → Disks → the OS disk → Size) and reboot; Ubuntu grows the root filesystem automatically.
- Or attach a data disk, format and mount it at
/var/lib/lancache, then reboot so first boot re-populates the cache directory on the larger volume.
The cache manages its own size (it evicts the least-recently-used objects to stay within its configured limit and keeps a minimum amount of free disk), so it will not fill the disk completely.
Troubleshooting
- A client is not being cached. Confirm the client's DNS is actually pointed at this VM and that the CDN domain is in the allow-list:
dig @<vm-ip> <cdn-domain>should return the cache IP. Check the NSG allows UDP+TCP 53 from the client. - Downloads fail after pointing DNS here. Ensure ports 80 and 443 are open in the NSG to your clients. HTTPS CDNs need 443; HTTP CDNs need 80.
- Container logs:
sudo docker logs lancache-monolithicandsudo docker logs lancache-dns. - Restart the stack:
sudo docker restart lancache-monolithic lancache-dns.
Support
cloudimg provides 24/7 support with a guaranteed 24 hour response SLA for all Azure Marketplace images. For assistance with this image, contact support through the cloudimg listing on Azure Marketplace or visit www.cloudimg.co.uk.