LanCache 2026.10.09
Overview
LanCache is the open source download cache from the LanCache.NET project. It keeps one copy of every game or update file that a client downloads, so the next client on your network gets the file from the cache instead of the internet.
This guide covers launching and verifying LanCache 2026.10.09 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. The guide hub of the listing describes the other VPN, proxy and remote access servers.
LanCache has no version numbers of its own. 2026.10.09 is the build date of the official lancachenet/monolithic image that this AMI runs.
Two parts work together:
- The cache (
lancachenet/monolithic): an nginx HTTP cache for the content CDNs of Steam, Epic Games, Battle.net, Riot, Xbox, PlayStation, Nintendo, Windows Update, Office and more, plus a pass-through on port 443 for the HTTPS-only CDNs. - The DNS server (lancachenet/lancache-dns): it answers those CDN names with the address of the cache, which sends clients to the cache without any client-side setting.
The list of cached CDN names is the community-maintained uklans/cache-domains list, as bundled in the pinned LanCache DNS image (120 domain names across 26 services).
What you get:
- Docker CE 29.9.2 from the signed apt repository of Docker, running the two official LanCache images, each pinned by digest:
lancachenet/monolithicbuilt 2026-10-09lancachenet/lancache-dnsbuilt 2026-09-27, with one SecureAnyCloud change: Ubuntu package updates applied (apt-get upgrade, which fixes OpenSSL CVE-2026-84782)
lancache-dns.serviceandlancache-cache.service: systemd units that run the two containerslancache-firstboot.service: per-instance setup on first bootlancache-netguard.service: the container firewall- Helpers:
lancache-selftest(health and security self-test) andlancache-acl(manages which networks may use the cache)
Default user: ubuntu. Architecture: x86_64. Root volume: 16 GiB gp3. The cache lives on the root volume (see Step 9 to grow it).
Security posture
An internet-reachable DNS server and HTTP proxy is a classic abuse target. Attackers can use it for DNS amplification, as an open proxy, or to reach services inside your VPC. This image closes each of those paths:
- Not an open resolver. BIND answers only the cached CDN names, each with the private IP of this instance. Every other name gets
REFUSED. BIND never recurses or forwards, has no control channel, rate-limits its answers, and runs as an unprivileged user with no Linux capabilities and a read-only file system. The default configuration of the upstream image, an open forwarding resolver, is never used. - Not an open proxy. The cache refuses any request whose target host is not on the CDN list (nginx
444: the connection is closed with no response). The check runs before nginx picks a route, and it covers every way a request can name a host:- the Host header
- a full URL in the request line
- a look-alike name such as
lancache.steamcontent.com.example.com - the client signature of Steam sent with any other host
- Only your networks can use it. On first boot, the instance reads the CIDR blocks of its VPC from the instance metadata service and writes them to
/etc/lancache/allowed-clients.txt. A firewall chain in front of the containers drops connections from every other source, and BIND accepts queries only from the same list.lancache-acladds an on-premises LAN (Step 6). It refuses0.0.0.0/0and any range wider than/8. - No path from the containers to the metadata service, your VPC or the instance itself. The
DOCKER-USERchain of Docker drops container traffic to 169.254.169.254 (instance metadata) and 168.63.129.16. The cache can open connections only to public internet addresses and to the Amazon DNS resolver (169.254.169.253). Private, VPC, link-local and loopback ranges are dropped, and so are connections to the own services of the host.dockerdandcontainerdare denied the metadata service too. The AMI is registered IMDSv2 only. - Hardened Docker. The Docker daemon has:
- no TCP API socket and no registry credentials
- published ports handled in the kernel (no userland proxy)
- no inter-container traffic
no-new-privileges, and core dumps off- size-rotated container logs
- Nothing per-instance ships. No container exists in the image, because the containers are created on your instance. The per-host identifiers of Docker, the client list, the DNS zone and the cache sizing are all created on the first boot of your instance. LanCache has no login and no password, so there is no credential to leak.
- Fail closed. The containers start only after first boot has written its configuration and the container firewall is loaded. If either is missing, nothing listens.
- Patched. The OS is fully patched at build time and unattended-upgrades stays on. Every installed package comes from Ubuntu main or the repository of Docker (no universe packages).
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- A subnet with outbound internet access (the cache fetches from the CDNs on the first download of each file)
- Clients that can reach the private IP of the instance: instances in the same VPC, or an office or LAN connected over a VPN or AWS Direct Connect
Recommended instance type: m5.large. LanCache is light on CPU and memory. Disk is what matters, because the cache can only hold as much as its volume.
Connecting to your instance
Connect to LanCache 2026.10.09 on Ubuntu 24.04 over SSH. The operating system is Ubuntu 24.04 LTS, and the SSH user is ubuntu.
Launch the instance
Option A: AWS Marketplace console
- Open the SecureAnyCloud Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- When the subscription is active, choose Launch your software.
- Choose Launch from EC2 Console. In Version, choose LanCache 2026.10.09 on Ubuntu 24.04, then choose your Region.
- Pick an instance type (
m5.largeis recommended, and the software charge is $0.04 per vCPU per hour) and your key pair. - Storage: give the root volume the size you want the cache to be, plus about 6 GiB. For example, 200 GiB holds about 155 GiB of cached downloads. You can also attach a separate data volume later (Step 9).
- Security group: the default group allows only SSH (22). Add the following rules, with your VPC CIDR (or LAN CIDR) as the source and never
0.0.0.0/0:- UDP 53 and TCP 53 (DNS)
- TCP 80 (the cache)
- TCP 443 (the HTTPS pass-through)
- Choose a subnet with internet access and leave the metadata defaults, because the image already requires IMDSv2. Then choose Launch.
Option B: AWS CLI
Run the following on your own workstation. Replace the AMI ID with the ID shown for your Region on the Marketplace launch page. Replace the VPC, subnet, key pair and address ranges with your own:
SG=$(aws ec2 create-security-group --group-name lancache \
--description "LanCache download cache" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol udp --port 53 --cidr <your-vpc-or-lan-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 53 --cidr <your-vpc-or-lan-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr <your-vpc-or-lan-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr <your-vpc-or-lan-cidr>
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=200,VolumeType=gp3}' \
--metadata-options HttpTokens=required,HttpPutResponseHopLimit=1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=lancache}]'HttpPutResponseHopLimit=1 keeps IMDSv2 tokens on the host itself, so a container cannot obtain a token even before the firewall rules apply. The firewall blocks the metadata service in either case.
Connect and read the instance information
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<instance-ip>First boot finishes within a minute of launch. It reads the private IP and VPC CIDR blocks of the instance, writes the client list, the DNS zone and the cache size, and then starts both containers. The instance information file holds no secret:
sudo cat /root/lancache-info.txt# LanCache on Ubuntu 24.04 (sac) - generated on first boot. There is NO login and NO credential. LANCACHE_IP=172.31.92.11 LANCACHE_DNS_SERVER=172.31.92.11 LANCACHE_HEARTBEAT_URL=http://172.31.92.11/lancache-heartbeat LANCACHE_ALLOWED_CLIENTS=172.31.0.0/16
# Point your clients' DNS at 172.31.92.11: it answers ONLY the game/OS-update CDN names LanCache caches (REFUSED for every # other name), so keep your normal resolver as the secondary or forward only those names to this instance. # Open UDP+TCP 53, TCP 80 and TCP 443 in the security group to your VPC/LAN CIDR only. Guide: see the MOTD.LANCACHE_IP is the private IP of the instance. Your clients use this address for both DNS and the cache.
Confirm LanCache is running
systemctl is-active docker.service lancache-netguard.service lancache-firstboot.service lancache-dns.service lancache-cache.serviceactive active active active activesudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'NAMES IMAGE STATUS PORTS lancache-monolithic 155817065b13 Up About a minute (healthy) 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 8080/tcp lancache-dns e8f1784f8732 Up About a minute 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udpPort 8080 (the nginx status page) is not published. It is reachable only inside the container.
Run the self-test
lancache-selftest checks that the cache and DNS work and that each closed path is still closed:
- Arbitrary names get
REFUSED. - Arbitrary hosts, full-URL requests, look-alike names and the Steam-signature trick are refused.
- An arbitrary TLS name is not passed through.
- The containers cannot reach the instance metadata service. An internet reachability check runs alongside, so a broken network cannot fake a pass.
sudo lancache-selftestSELFTEST_OK: heartbeat 204; DNS maps the CDN names to 172.31.92.11 and REFUSES others; arbitrary Host, regex-location, absolute-form, suffix and Steam-UA requests closed (444); arbitrary SNI not relayed; containers cannot reach instance metadataPoint your clients at the cache
Clients use LanCache by resolving the CDN names to it. LanCache answers only those names and refuses everything else, so it cannot be the only DNS server of a client. Forward just the CDN names to LanCache from the DNS that your clients already use:
- Route 53 Resolver: a forwarding rule per name in
/etc/lancache/domains.txt, withLANCACHE_IPas the target. - Active Directory DNS: conditional forwarders.
- Unbound, dnsmasq or Pi-hole: forward-zone or server entries for the same names.
Everything else keeps resolving as before. To try one client quickly, set its DNS server to LANCACHE_IP. Every non-CDN name fails on that client.
Check the answers from the instance itself:
dig +short @127.0.0.1 lancache.steamcontent.com dig +short @127.0.0.1 download.epicgames.com172.31.92.11 172.31.92.11Any other name is refused, with no answer:
dig @127.0.0.1 example.com | grep -E 'status|ANSWER:';; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 22711 ;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1The cached services and names:
python3 -c "import json; print(', '.join(s['name'] for s in json.load(open('/var/lib/lancache/cachedomains/cache_domains.json'))['cache_domains']))" grep -c . /etc/lancache/domains.txtarenanet, blizzard, bsg, cityofheroes, cod, daybreak, epicgames, frontier, neverwinter, nexusmods, nintendo, origin, pathofexile, renegadex, riot, rockstar, sony, square, steam, teso, test, uplay, warframe, wargaming, wsus, xboxlive 120Steam is handled through lancache.steamcontent.com, the name that the documented Steam integration of LanCache relies on. Once the name resolves to the cache, the Steam client sends its content downloads there. The cache accepts the Steam client on the own CDN host names of Steam only.
Choose which networks may use the cache
Only the ranges in /etc/lancache/allowed-clients.txt can query the DNS server or use the cache. First boot writes the CIDR block(s) of your VPC:
sudo lancache-acl list# LanCache clients (sac): DNS :53 and the cache :80/:443 answer ONLY these IPv4 ranges.
# First boot wrote this instance's VPC CIDR block(s). Add an on-premises LAN with:
sudo lancache-acl add <CIDR> 172.31.0.0/16To serve an office LAN that reaches the VPC over a VPN or Direct Connect, add its range. Also allow the range in the security group:
sudo lancache-acl add 192.168.10.0/24
sudo lancache-acl remove 192.168.10.0/24lancache-acl updates the client list of BIND and the container firewall in one step, and restarts the DNS container. It refuses 0.0.0.0/0 and any range wider than /8.
Watch a download being cached
Request a small Office file through the cache twice. The first request is fetched from the CDN (MISS). Every later request, from any client, is served from the cache (HIT):
for i in 1 2; do curl -s -o /dev/null -D - -H 'Host: officecdn.microsoft.com' http://127.0.0.1/pr/wsus/ofl.cab | grep -iE '^HTTP|X-Upstream-Cache-Status'; doneHTTP/1.1 200 OK X-Upstream-Cache-Status: MISS HTTP/1.1 200 OK X-Upstream-Cache-Status: HITA host that is not on the list is refused. The connection is closed, so curl reports 000:
curl -s -o /dev/null -w 'example.com via the cache: HTTP %{http_code}\n' -m 10 -H 'Host: example.com' http://127.0.0.1/ || echo "the cache closed the connection (curl exit $?)"example.com via the cache: HTTP 000 the cache closed the connection (curl exit 52)Metadata and VPC access is blocked for the containers
From inside the cache container, an IMDSv2 token request times out (curl exit code 28):
sudo docker exec lancache-monolithic curl -s -m 5 -o /dev/null -w 'HTTP %{http_code}\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/token; echo "curl exit $?"HTTP 000 curl exit 28These are the rules that block it:
sudo iptables -S DOCKER-USER
sudo iptables -S LANCACHE-GUARD | tail -4-N DOCKER-USER -A DOCKER-USER -d 169.254.169.254/32 -j DROP -A DOCKER-USER -d 168.63.129.16/32 -j DROP -A DOCKER-USER -j LANCACHE-GUARD -A LANCACHE-GUARD -d 240.0.0.0/4 -i docker0 -j DROP -A LANCACHE-GUARD -d 172.31.0.0/16 -i docker0 -j DROP -A LANCACHE-GUARD -s 172.31.0.0/16 -o docker0 -j RETURN -A LANCACHE-GUARD -o docker0 -j DROPThe last three lines are the client list. The cache may not open connections into the VPC, connections from the VPC are let through, and every other source is dropped. lancache-netguard loads these rules before Docker starts, and again after any Docker restart.
Cache storage and size
Cached files live under /var/lib/lancache/cache on the root volume. First boot sizes the cache to 80% of the free space of that file system, less 1 GiB:
df -h /var/lib/lancache/cache | tail -1 grep -v '^#' /etc/lancache/lancache.env/dev/root 15G 4.3G 11G 30% / CACHE_DISK_SIZE=7353m CACHE_INDEX_SIZE=250m MIN_FREE_DISK=1g UPSTREAM_DNS=169.254.169.253 NOFETCH=trueTo give the cache more room, choose one of the following:
- Grow the root volume. Modify the EBS volume in the console, then reboot (cloud-init grows the partition and the file system at boot) or run
sudo growpart /dev/nvme0n1 1 && sudo resize2fs /dev/nvme0n1p1. - Mount a dedicated data volume at
/var/lib/lancache/cache. Attach the volume, then run the commands that follow.
text lsblk -o NAME,SIZE,SERIAL # the new volume's SERIAL is its volume ID without the dash sudo systemctl stop lancache-cache sudo mkfs.ext4 /dev/nvme1n1 echo "UUID=$(sudo blkid -s UUID -o value /dev/nvme1n1) /var/lib/lancache/cache ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab sudo mount /var/lib/lancache/cache
Then raise CACHE_DISK_SIZE in /etc/lancache/lancache.env (to about 80% of the new space) and run sudo systemctl restart lancache-cache. The cache container takes ownership of the new file system when it starts.
UPSTREAM_DNS is the Amazon DNS resolver that the cache uses to reach the CDNs. NOFETCH=true makes the cache use the pinned CDN list on the image instead of downloading the list from GitHub on every start.
Logs
Cache access logs are in /var/lib/lancache/logs. They rotate daily, and seven days are kept. Each line names the service, the client address, the request and whether the request was a cache HIT or MISS:
sudo tail -n 2 /var/lib/lancache/logs/access.log[wsus] 172.17.0.1 / - - - [27/Oct/2026:15:03:05 +0000] "GET /pr/wsus/ofl.cab HTTP/1.1" 200 19047 "-" "curl/8.5.0" "HIT" "officecdn.microsoft.com" "-" [example.com] 172.17.0.1 / - - - [27/Oct/2026:15:03:05 +0000] "GET / HTTP/1.1" 444 0 "-" "curl/8.5.0" "-" "example.com" "-"These logs contain the IP addresses of your clients and the files they download. The messages of the DNS server go to the journal (sudo journalctl -u lancache-dns).
How the fail-closed start works
lancache-firstboot.serviceruns once, before both container units. If it cannot read the private IP or the VPC CIDR from the instance metadata service, it writes nothing, neither container starts, and the next boot tries again.lancache-dns.serviceandlancache-cache.servicestart only when/var/lib/sac/data/lancache-readyexists. Before each start,lancache-preflightrefuses to continue unless all of the following hold:- the pinned image is present
- its configuration exists
- the container firewall (metadata DROP, client list, host guard) is loaded
Updates
- Ubuntu packages: unattended-upgrades applies Ubuntu security updates automatically.
- Docker CE: the apt repository of Docker stays enabled, so
sudo apt-get update && sudo apt-get upgradeinstalls the Docker updates. - LanCache images: the two images are pinned by digest and are not updated in place. SecureAnyCloud ships newer LanCache builds as new versions in the listing.
The DNS image still contains the upstream dnstool config generator, built with Go 1.27.1, which carries four Go standard-library advisories fixed in Go 1.27.3. This image never runs dnstool. The entry point of the container is BIND, and the CDN list is copied out of the image without starting it.
Security recommendations
- Open ports 53, 80 and 443 in the security group to your VPC or LAN ranges only. The client list already drops other sources, but the security group is the first wall.
- Restrict SSH (22) to your management address.
- Keep the cache in a private subnet if all your clients are inside AWS. It needs outbound internet access (a NAT gateway is enough), not inbound.
- Size the volume for your catalogue. A full modern game can be 100 GiB or more.
Support and licensing
- LanCache (
lancachenet/monolithic,lancachenet/lancache-dns) and theuklans/cache-domainslist are MIT-licensed. The license texts, the exact image digests and commits, and the Dockerfile of the DNS image are in/usr/share/doc/sac-lancache/. Docker CE is Apache-2.0. BIND and nginx inside the images carry their own licenses. - SecureAnyCloud provides 24/7 technical support by email and live chat: sales@secureanycloud.com.
- LanCache, Steam, Epic Games, Battle.net, Xbox, PlayStation, Nintendo and Windows are trademarks of their respective owners. SecureAnyCloud is not affiliated with or endorsed by any of them.
Deploy on AWS
Launch LanCache 2026.10.09 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com