Setup Local FreeBSD SUS Part II

Setting Up SUS on FreeBSD, take 2

After some testing, my previous version of SUS, I noticed that packages are not working… So back to the drawing board. This version is downloading packages, so I would call it good for now. I plan to install new FreeBSD shortly and will do some more testing. If I find some more fixes, well, the saga will continue. I will not repeat the storage and ZFS setup, so please check that in Setup Local FreeBSD SUS (Software Update Server) before continuing. If you want to learn more about ZFS, then I recommend my article that explains ZFS in detail: ZFS (Zettabyte File System) basics

This guide shows how to build a local FreeBSD update server that really works.
It is simple.
It is fast.
Uses Nginx as a reverse proxy with cache.
Saves bandwidth and makes updates very quick.

This is V2 of the SUS setup.
It is clean and tested on FreeBSD 15 and FreeBSD 16.

1. What This SUS Does

Keeps FreeBSD packages close to you.

Uses Nginx to fetch packages from the main FreeBSD servers.
Stores packages in a local cache.
Works even if the upstream server is slow.
Supports many FreeBSD versions.

Needs almost no maintenance.

2. Why This SUS Works

Many SUS guides fail because:

Nginx cannot resolve DNS.
Nginx regex is wrong.
The cache zone is wrong.
FreeBSD 16 has limited packages.

This setup fixes all of that.
Uses its own resolver.
The correct proxy rules.
A clean cache path.
Matches the real FreeBSD package layout.

4. Full Nginx Config (Copy & Paste)

This is the full working config.
Supports FreeBSD 15 and 16.
Uses HTTPS.
It uses cache.
Utilizes a DNS resolver.

http {
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;

    proxy_cache_path 
        levels=1:2
        keys_zone=pkgcache:500m
        max_size=20g
        inactive=30d;

    server {
        listen 80;
        server_name sus.local;

        # FreeBSD package mirror
        location ~ ^/FreeBSD:(\d+):amd64/(.*)$ {
            proxy_cache pkgcache;
            proxy_pass https://pkg0.tuk.freebsd.org/FreeBSD:$1:amd64/$2;
            proxy_ssl_server_name on;
            proxy_set_header Host pkg0.tuk.freebsd.org;
            add_header X-Cache $upstream_cache_status;
        }

        # Default
        location / {
            return 404;
        }
    }
}

 5. Test FreeBSD 15 (Full Repo)

FreeBSD 15 has a full package repo.
These tests should work:

root@OF:~/test # curl -I http://sus.local/FreeBSD:15:amd64/latest/Latest/pkg.pkg
HTTP/1.1 200 OK
Server: nginx/1.28.2
Date: Fri, 03 Apr 2026 16:55:10 GMT
Content-Type: application/octet-stream
Content-Length: 6885437
Connection: keep-alive
Last-Modified: Sat, 28 Mar 2026 01:03:21 GMT
ETag: "69c728d9-69103d"
Cache-Control: private, no-cache, max-age=0
Accept-Ranges: bytes
X-Cache: MISS

root@OF:~/test # curl -I http://sus.local/FreeBSD:16:amd64/latest/Latest/pkg.pkg
HTTP/1.1 200 OK
Server: nginx/1.28.2
Date: Fri, 03 Apr 2026 16:55:10 GMT
Content-Type: application/octet-stream
Content-Length: 6919933
Connection: keep-alive
Last-Modified: Sat, 21 Mar 2026 01:13:58 GMT
ETag: "69bdf0d6-6996fd"
Cache-Control: private, no-cache, max-age=0
Accept-Ranges: bytes
X-Cache: MISS
7. Notes

This SUS works for all FreeBSD versions that have real package repos.
FreeBSD 16 CURRENT has limited packages.
404 for missing paths is normal.
Cache makes updates very fast.
Nginx resolver is required.
This setup is stable and simple.

 

This is V2 of the SUS setup.
For the original article and background story, see: Setup Local FreeBSD SUS (Software Update Server)