Athens Go Module Proxy on AWS User Guide
Overview
This image runs Athens, the 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 image delivers it fully installed and hardened: Athens itself binds to the loopback interface only, and nginx is the single network facing surface, terminating TLS on port 443 and fronting 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.
The module cache lives on a dedicated, independently resizable EBS data volume mounted at /var/lib/athens, separate from the operating system disk, so the cache has room to grow. Athens 0.18.1 was installed from the official upstream release and verified against its published SHA256 checksum at build time.
Secure by default: per instance credentials
Nothing secret is baked into this image. On the first boot of every instance, the athens-firstboot service:
- 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, and - 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 you need:
- 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 allowing 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
Step 1: Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for Athens Go Module Proxy. Select the cloudimg listing, choose Select, then 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, and either 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.
Select Launch instance. First boot initialisation takes a few seconds after the instance state becomes Running and the status checks pass.
Step 2: Launch the Instance from the AWS CLI
The following block launches an instance from the cloudimg 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.
Step 3: Connect to Your Instance
Connect over SSH using 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>
Step 4: 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.txt
The 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 is the credential for your private module proxy.
Step 5: Confirm the proxy is running
Athens runs as a systemd service bound to 127.0.0.1:3000 only, with nginx terminating TLS on port 443 as the single network facing surface. Confirm 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 -version

Athens is listening on 127.0.0.1:3000 and never on a public interface; nginx owns port 443. This is what keeps the proxy from being an open module relay.
Step 6: Verify the authentication boundary
nginx fronts the entire proxy with HTTP basic authentication, so an unauthenticated request is rejected while an authenticated request serves the module protocol. An unauthenticated /healthz probe is available for load balancers. Substitute 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/healthz

Step 7: Point 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 served at /etc/nginx/tls/athens.crt), then:
# 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.2
The 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. You can confirm 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/athens

To roll the proxy out across a team, set the same GOPROXY and SSL_CERT_FILE on every developer machine and CI runner. For production use, replace the self signed certificate with one signed by your own certificate authority or a public CA for your domain, and 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/cloudimg-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
This Athens image is supported 24/7 by cloudimg. 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, contact support@cloudimg.co.uk. 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 cloudimg support services.