Athens Go proxy
Overview
Athens is an open-source, enterprise-ready implementation of the Go module proxy, the GOPROXY protocol built into the Go toolchain. Point your developers and CI pipelines at an Athens server, and every go build, go test and go mod download fetches modules through it. Athens downloads each module version once, caches it on disk, and serves every later request from that cache.
The result is faster builds, far less duplicated download traffic, and reproducible builds that keep working even when an upstream module is deleted, retagged, or its VCS host is unreachable. This SecureAnyCloud image deploys Athens Go Module Proxy on Ubuntu 24.04 on Azure, secured by default.
The image installs Athens 0.18.1 from the official upstream release (a single, self-contained Go binary) together with the official Go 1.26.5 toolchain, because Athens shells out to the go command to fetch modules on a cache miss. Athens has no web interface. It speaks the Go module download HTTP protocol and is driven by the go command.
The Athens server is bound to the loopback interface only (127.0.0.1:3000), and nginx is the only network-facing service. nginx terminates TLS on port 443 and fronts the entire proxy with HTTP basic authentication, so the proxy is never an open module relay.
Secure by default, with no shared credentials. Athens ships with no authentication of its own, so an unprotected Athens is an open proxy. This image never exposes it that way, and nothing secret is baked into it. On the first boot of every instance, Athens generates a unique HTTP basic authentication username and password and a unique self-signed TLS certificate, and writes the credentials to a root-only file. Unauthenticated requests are rejected, and the module protocol is reachable only over TLS with the per-instance credentials.
What you get:
- Athens 0.18.1 from the official upstream release binary, run under systemd (
athens.service) as an unprivilegedathensuser, with the proxy bound to127.0.0.1:3000 - The official Go 1.26.5 toolchain at
/usr/local/go, which Athens uses to fetch modules from the upstream Go mirror (falling back to direct VCS) on a cache miss - nginx (
nginx.service) terminating TLS on port 443 as the only network-facing service, fronting the whole proxy with HTTP basic auth, plus an unauthenticated/healthzendpoint for load balancer probes - A per-instance HTTP basic authentication credential and TLS certificate, generated fresh on first boot, with the per-instance values written to
/root/athens-credentials.txt - The module cache on a dedicated data disk mounted at
/var/lib/athens, separate from the operating system disk
Prerequisites
- An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
- A subscription to the Athens listing on the Azure Marketplace
- Network security group (NSG) rules that allow TCP 22 (administration) and TCP 443 (HTTPS, for the GOPROXY API) from the developers and build agents that use the proxy
Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a team module proxy. Increase the size and enlarge the data disk when you cache a large module graph or serve many concurrent CI jobs.
Deploy from the Azure Portal
Search the Azure Marketplace for Athens, select the SecureAnyCloud publisher, and choose Create.
Configure the NSG to allow TCP 443 from the developer workstations and build agents that will use the proxy, and TCP 22 for administration. Restrict port 443 to the networks you serve, because a module proxy rarely needs to be reachable from the whole internet.
Deploy from the Azure CLI
RG="athens-prod"; LOCATION="eastus"; VM_NAME="athens1" IMAGE_URN="sac1647283583153:athens-go-proxy-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:athens-go-proxy-ubuntu-24-04:default:latest
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$IMAGE_URN" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 443 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002First boot and per-instance credentials
On first boot, the image resolves this VM's IP address. It generates a per-instance HTTP basic authentication username and password and a per-instance TLS certificate, and writes everything to /root/athens-credentials.txt. This completes within seconds.
SSH in as azureuser and read the credentials file:
sudo cat /root/athens-credentials.txtThe file is 0600 root:root. It records the proxy user and password, the HTTPS proxy URL, and a ready-to-paste GOPROXY example. These values are unique to this instance.
Confirm the services are running
Run the commands below. Confirm that athens.service and nginx.service are both active and that athens -version reports 0.18.1. The ss output shows that nginx owns port 443 while the Athens proxy is bound to loopback only on port 3000.
systemctl is-active athens.service nginx.service /opt/athens/athens -version sudo ss -tlnp | grep -E ':443 |:3000 'Confirm the proxy is never open
The module proxy is reachable only through nginx on port 443, and only with the per-instance HTTP basic authentication. An unauthenticated module request returns 401. A request with the per-instance credentials returns 200. Only the /healthz load balancer probe is served without credentials.
The block below reads the credentials from the instance credentials file, so it works unchanged on any instance.
PROXY_USER=$(sudo grep -E '^ATHENS_PROXY_USER=' /root/athens-credentials.txt | cut -d= -f2-)
PROXY_PASS=$(sudo grep -E '^ATHENS_PROXY_PASSWORD=' /root/athens-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'healthz (no auth) -> HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -sk -o /dev/null -w 'list (no auth) -> HTTP %{http_code}\n' https://127.0.0.1/rsc.io/quote/@v/list
curl -sk -u "$PROXY_USER:$PROXY_PASS" -o /dev/null -w 'list (with auth) -> HTTP %{http_code}\n' https://127.0.0.1/rsc.io/quote/@v/listThe -k flag tells curl to accept the self-signed per-instance certificate. The authenticated request returns the list of versions Athens can serve for the module, which it assembles from its own cache and the upstream mirror.
Point the Go toolchain at the proxy
Set GOPROXY to the authenticated HTTPS URL of this proxy and run go mod download. The module is fetched through Athens, which caches it and serves it.
The block below runs entirely on this VM against 127.0.0.1 to demonstrate the round trip. On a workstation, use this VM's address instead (see Step 8).
PROXY_USER=$(sudo grep -E '^ATHENS_PROXY_USER=' /root/athens-credentials.txt | cut -d= -f2-)
PROXY_PASS=$(sudo grep -E '^ATHENS_PROXY_PASSWORD=' /root/athens-credentials.txt | cut -d= -f2-)
export PATH=/usr/local/go/bin:$PATH export SSL_CERT_FILE=/etc/nginx/tls/athens.crt
# trust this VM's self signed certificate export GOSUMDB=off export GOPROXY="https://$PROXY_USER:$PROXY_PASS@127.0.0.1/" export GOPATH=$(mktemp -d) GOMODCACHE=$(mktemp -d) HOME=$(mktemp -d)
cd "$(mktemp -d)" go mod download -x github.com/pkg/errors@v0.9.1 echo "go mod download exit code: $?"Every request in the trace is served with HTTP 200 through the proxy on 127.0.0.1, and go mod download exits 0. The module has now been fetched once and cached.
The module cache on the dedicated data disk
Athens stores every fetched module in its on-disk cache on the dedicated data disk mounted at /var/lib/athens. The cache has room to grow and is separate from the operating system disk.
Confirm the mount and inspect the cache:
df -h /var/lib/athens
sudo find /var/lib/athens/storage -maxdepth 3 -mindepth 1 -type dThe output shows the data disk mounted at /var/lib/athens. The cache lists every module Athens has fetched so far, each ready to be served to your whole team without touching the internet again.
Use the proxy from your team and CI
On any developer workstation or CI agent, point the Go toolchain at this instance. Replace <vm-ip> with this instance's address (or a DNS name you point at it), and use the per-instance credentials from /root/athens-credentials.txt.
# trust this instance's certificate (copy /etc/nginx/tls/athens.crt from the VM), then:
export SSL_CERT_FILE=/path/to/athens.crt
export GOPROXY="https://<user>:<password>@<vm-ip>/"
export GOSUMDB=off go mod download go build ./...For CI, set the same GOPROXY, GOSUMDB and certificate trust as environment variables in your pipeline. Every job then pulls modules from the shared cache instead of the public internet, which is faster and keeps your builds reproducible.
Use a real domain and certificate for production
The per-instance certificate is self-signed, so clients must trust it explicitly. For production, put a DNS name and a CA-signed certificate in front of the proxy by replacing the per-instance certificate in /etc/nginx/tls. Clients then trust the transport with no extra configuration.
# replace the self signed certificate with your CA signed certificate + key, then reload nginx
sudo cp your-cert.crt /etc/nginx/tls/athens.crt
sudo cp your-cert.key /etc/nginx/tls/athens.key
sudo systemctl reload nginx
# point GOPROXY at https://<your-domain>/ with the per instance credentialsSecurity recommendations
- Restrict the NSG. Allow TCP 443 only from the developer subnets and build agents that use the proxy, and TCP 22 only from your administration network. A module proxy rarely needs to be public.
- Protect the proxy password. It lives in
/root/athens-credentials.txt(0600 root:root). The proxy is reachable only through nginx and only with this password. To rotate it, update/etc/nginx/athens.htpasswdwithhtpasswdand reload nginx. - Use a real certificate for production. The per-instance certificate is self-signed. Put a CA-signed certificate and a DNS name in front of the proxy so clients trust the transport without extra configuration.
- Size the data disk for your module graph. The cache grows as your team pulls more modules. Monitor
/var/lib/athensand enlarge the data disk when needed. - Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Support and Licensing
Athens is open-source software distributed under the MIT License. This SecureAnyCloud image bundles the unmodified official Athens release binary and the official Go toolchain.
SecureAnyCloud provides the packaging, the systemd hardening, the nginx TLS front, the loopback-only proxy with per-instance basic auth, the per-instance credential automation, the dedicated data disk for the cache, this deployment guide, and 24/7 support with a guaranteed 24 hour response SLA.
SecureAnyCloud is not affiliated with or endorsed by the Athens project. Athens is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find Athens Go Module Proxy on Ubuntu 24.04 LTS on the Azure Marketplace, published by SecureAnyCloud. Deploy from the Portal or the Azure CLI as shown above.
Need help?
Email sales@secureanycloud.com for deployment help, configuration questions, or licensing enquiries.
Deploy on Azure
Launch Athens Go Module Proxy 0.18.1 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Athens is an open-source, enterprise-ready implementation of the Go module proxy, the GOPROXY protocol built into the Go toolchain. Point your developers and CI pipelines at an Athens server, and every go build, go test and go mod download fetches modules through it. Athens downloads each module version once, stores it in its own on-disk cache, and serves every later request from that cache.
The result is faster builds, far less duplicated download traffic, and reproducible builds that keep working even when an upstream module is deleted, retagged, or its version control host is unreachable.
Athens speaks the Go module download HTTP protocol and is driven entirely by the standard go command, so there is no web console to manage. This SecureAnyCloud image delivers it fully installed and hardened. Athens binds to the loopback interface only, and nginx is the single network-facing service. nginx terminates TLS on port 443 and fronts the entire proxy with HTTP basic authentication, so it is never an open relay.
The official Go toolchain and git are installed on the image because Athens shells out to the go command to fetch modules from the upstream Go mirror, or directly from a module's version control host, on a cache miss.
What you get:
- Athens 0.18.1, installed from the official upstream release and verified against its published SHA256 checksum at build time
- A dedicated, independently resizable EBS data volume mounted at
/var/lib/athensfor the module cache, separate from the operating system disk so the cache has room to grow
Secure by default: per-instance credentials
Nothing secret is baked into this image. On the first boot of every instance, the athens-firstboot service does the following:
- Resolves the instance public IP through the EC2 Instance Metadata Service (IMDSv2)
- Generates a unique self-signed TLS certificate whose subject alternative names cover the instance public IP, its hostname and
127.0.0.1 - Generates a unique HTTP basic authentication username and password for the proxy and writes the nginx
htpasswd - Writes the credentials, the HTTPS proxy URL and a ready-to-paste
GOPROXYexample to/root/athens-aws-credentials.txt(mode0600, root only)
Every instance therefore gets its own certificate and its own password. Unauthenticated requests are rejected with 401, and the module protocol is reachable only over TLS with the per-instance credentials.
Prerequisites
Before you deploy this image, make sure you have:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 (SSH) from your management network and inbound port 443 (HTTPS) from the workstations and CI agents that will use the proxy
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and choose Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Athens Go Module Proxy. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login). Under Network settings, select your VPC and subnet, then create or select a security group that opens port 22 from your management network and port 443 from your developer and CI networks.
Leave the root volume at the default size or larger. The module cache lives on a separate data volume that is provisioned automatically.
Choose Launch instance. First-boot initialisation takes a few seconds after the instance state becomes Running and the status checks pass.
Launch the instance from the AWS CLI
Run the following block to launch an instance from the SecureAnyCloud Athens Marketplace AMI into an existing subnet and security group.
Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens port 22 and port 443.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=athens-go-proxy}]'When the instance reaches the Running state and its status checks pass, note its public IP address or DNS name from the EC2 console or with aws ec2 describe-instances.
Connect to your instance
Connect over SSH with your key pair and the login user for your operating system variant.
OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i /path/to/your-key.pem ubuntu@<public-ip>Retrieve the per-instance proxy credentials
The unique username and password generated on first boot are in a root-only file. Read them with sudo:
sudo cat /root/athens-aws-credentials.txtThe file contains:
ATHENS_PROXY_USERandATHENS_PROXY_PASSWORD: the HTTP basic auth username and password for this instanceATHENS_PROXY_URL: the HTTPS proxy URL,https://<instance-public-ip>/- A ready-to-paste
GOPROXYexample
Keep this file secret. It holds the credentials for your private module proxy.
Confirm the proxy is running
Athens runs as a systemd service bound to 127.0.0.1:3000 only. nginx terminates TLS on port 443 as the single network-facing service.
Confirm that both services are active and that Athens is listening on loopback only:
systemctl is-active athens.service nginx.service
sudo ss -ltnp | grep -E ':3000|:443' /opt/athens/athens -versionAthens listens on 127.0.0.1:3000 and never on a public interface, while nginx owns port 443. This is what keeps the proxy from being an open module relay.
Verify the authentication boundary
nginx fronts the entire proxy with HTTP basic authentication. An unauthenticated request is rejected, and an authenticated request serves the module protocol. An unauthenticated /healthz probe is available for load balancers.
Run the following, substituting the username and password from your credentials file:
# no credentials -> 401 Unauthorized (the proxy is never open)
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1/rsc.io/quote/@v/list
# with the per instance credentials -> 200 and the list of module versions
curl -sk -u "$ATHENS_PROXY_USER:$ATHENS_PROXY_PASSWORD" https://127.0.0.1/rsc.io/quote/@v/list
# unauthenticated load-balancer liveness probe -> 200
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1/healthzPoint the go command at your proxy
On each workstation and CI agent, trust this instance's self-signed certificate and set GOPROXY to the authenticated HTTPS URL. First copy the certificate off the instance (it is at /etc/nginx/tls/athens.crt), then run:
# trust this instance's certificate (or add it to your system trust store)
export SSL_CERT_FILE=/path/to/athens.crt
# point the go toolchain at your private Athens proxy
export GOPROXY="https://<user>:<password>@<public-ip>/"
export GOSUMDB=off
# every module now flows through Athens and is cached on the instance go mod download rsc.io/quote@v1.5.2The first time a module version is requested, Athens fetches it from the upstream Go mirror (falling back to the module's version control host), stores it in its on-disk cache on the data volume, and serves it. Every later request for that version is served straight from the cache.
Confirm that the module landed in the cache and that the cache is on the dedicated data volume:
ls -la /var/lib/athens/storage/rsc.io/quote/v1.5.2/ df -h /var/lib/athensTo roll the proxy out across a team, set the same GOPROXY and SSL_CERT_FILE on every developer machine and CI runner.
For production, replace the self-signed certificate with one signed by your own certificate authority or a public CA for your domain. Place the instance behind a load balancer if you need horizontal scale.
Configuration and data layout
Path Purpose
/opt/athens/athens The Athens binary
/etc/athens/config.toml Athens configuration (loopback bind, disk storage, upstream mirror)
/var/lib/athens/storage The on-disk module cache, on the dedicated data volume
/etc/nginx/sites-available/sac-athens The nginx reverse proxy and TLS configuration
/etc/nginx/tls/athens.crt and athens.key The per-instance self-signed certificate and key
/etc/nginx/athens.htpasswd The per-instance basic auth password file
/root/athens-aws-credentials.txt The generated per-instance credentials (mode 0600)
To change the upstream module source, worker counts or storage settings, edit /etc/athens/config.toml and run sudo systemctl restart athens.service.
To change the proxy password, update /etc/nginx/athens.htpasswd with htpasswd and run sudo systemctl reload nginx.
Support
SecureAnyCloud supports this Athens image 24/7. Contact sales@secureanycloud.com for deployment help, GOPROXY rollout across teams and CI, upstream and fallback proxy configuration, nginx TLS with your own domain and certificate, module cache sizing, Athens version upgrades, or any other question. Critical issues receive a one hour average response time.
Athens is a trademark of its respective owner. This is a repackaged open-source software product with additional charges for SecureAnyCloud support services.
Deploy on AWS
Launch Athens Go Module Proxy on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need help?
Our support team is available 24/7.
sales@secureanycloud.com