Deployment guide

Quay Ubuntu 24.04

Overview

This image runs Project Quay 3.17.3, the open source container image registry that powers Quay.io, on Ubuntu 24.04 LTS. Project Quay is the upstream community project of Red Hat Quay. It provides private image repositories with fine-grained access control across users, organizations, teams and robot accounts. It also provides a standards-compliant OCI and Docker v2 registry API, tag lifecycle management with expiration and auto-pruning, and a complete REST API for automation.

SecureAnyCloud delivers the full upstream service topology natively under systemd, reverse-proxied behind nginx, with PostgreSQL 16 and Redis 7 already configured. A private container registry is operational within minutes of launch.

What you get:

  • Project Quay 3.17.3 built from the official source release into /opt/quay, running in a dedicated Python virtual environment
  • The complete upstream process topology under one systemd unit (quay.service): the web, registry and security scanning application servers, plus the full set of background workers for garbage collection, notifications, quotas and auto-pruning
  • PostgreSQL 16 as the primary database and Redis 7 for build logs and events
  • nginx publishing the registry and web UI on port 80
  • Registry storage on the instance disk at /var/lib/quay/storage
  • Secure by default: no administrator account and no shared secret ship in the image. On first boot, fresh secret keys and a fresh database password are generated. A unique administrator account plus a scoped API access token are written to a root-only file. Anonymous access and open self-registration are disabled.
  • Per-boot swap on the Azure ephemeral resource disk (quay-swap.service), giving the worker fleet headroom on smaller VM sizes
  • An Ubuntu 24.04 LTS base, patched at build time, with unattended security upgrades enabled
  • 24/7 SecureAnyCloud support

Prerequisites

  • An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region
  • Recommended size: Standard_B2ms (2 vCPU / 8 GiB RAM). Standard_B2s (2 vCPU / 4 GiB RAM) works for evaluation, and the image automatically provisions swap on the VM's ephemeral resource disk.
  • NSG inbound: allow 22/tcp from your management network and 80/tcp for the registry and web interface.
  • Project Quay serves plain HTTP on port 80. For production or shared access, terminate TLS with your own domain (see the final step).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Project Quay by SecureAnyCloud, and select Create.

On Basics, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).

Then choose Review + create, followed by Create.

Step 2 - Deploy from the Azure CLI

Accept the Marketplace terms once per subscription, then create the VM and open port 80:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:quay-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name quay \
  --image sac1647283583153:quay-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard
# Open the HTTP port so you can reach the registry and web interface
az vm open-port --resource-group <your-rg> --name quay --port 80 --priority 900

Step 3 - Retrieve the per-VM admin credentials

Nothing secret is baked into the image. On the very first boot, a two-stage service pair runs.

First, quay-firstboot.service generates a fresh secret key, a fresh database secret key and a fresh database password, and writes the instance address into the configuration. Then quay-admin-init.service creates a unique admin account plus a scoped OAuth access token through Quay's own bootstrap API, which only works while the database is empty.

The credentials are written to /root/quay-credentials.txt, which only root can read. SSH in as azureuser and read them:

$
sudo cat /root/quay-credentials.txt
# Project Quay - generated on first boot by quay-admin-init.service.
# These credentials are unique to THIS VM. Store them somewhere safe. quay.url=http://20.55.10.42/ quay.admin.user=admin quay.admin.pass=Xq7pR2mK9wU4nZ8vB3hL6yD1 quay.api.token=1x2Y3z4A5b6C7d8E9f0G1h2I3j4K5l6M7n8O9p0Q
# Canonical keys consumed by the sac smoke verifier + guide substitution: QUAY_ADMIN_PASSWORD=<set-at-first-boot> QUAY_ACCESS_TOKEN=<set-at-first-boot>

The first-boot services are ordered before the application, so the registry starts only after every per-VM secret has been generated. The values above are an example. Your instance has its own unique credentials.

On first boot, the database schema check and admin creation can take two to three minutes after SSH first answers. If the file is not there yet, wait a moment and try again once the sentinel /var/lib/sac/data/quay-firstboot.done exists.

Step 4 - Confirm the services are running

Check that PostgreSQL, Redis, the Quay process tree and nginx are all active:

sudo systemctl is-active postgresql redis-server quay nginx

All four report active. quay.service runs Quay's own supervisord process tree, which mirrors the upstream topology: the web, registry and security scanning application servers, plus the background workers.

nginx publishes the interface on port 80 and proxies to Quay's own nginx on 8080. Confirm that both ports are listening:

sudo ss -tln | grep -E ':80 |:8080 '

Step 5 - Confirm the web endpoints

Quay's built-in health checker verifies the database, Redis and storage, and returns 200. The registry API and the REST API both refuse anonymous requests with 401, which is the secure default. Run these three requests:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/health/instance
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/v2/
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/api/v1/user/

Step 6 - Sign in to the web UI

Browse to http://<vm-ip>/ and sign in as admin with the password from /root/quay-credentials.txt.

After signing in, you land on the repositories view. The screenshots in this guide show a registry populated with two small example images. A freshly deployed instance starts empty and is ready for your own images.

Step 7 - Push your first container image

The instance ships with skopeo, so you can copy an image into your registry straight from the VM itself. This exercises the real Docker v2 push and pull path end to end. Replace the password with the value from /root/quay-credentials.txt:

sudo skopeo copy --dest-tls-verify=false \
  --dest-creds 'admin:<QUAY_ADMIN_PASSWORD>' \
  docker://public.ecr.aws/docker/library/alpine:3.20 \
  docker://localhost/admin/alpine:3.20

Read the image back from the registry to prove the round trip:

sudo skopeo inspect --tls-verify=false \
  --creds 'admin:<QUAY_ADMIN_PASSWORD>' \
  docker://localhost/admin/alpine:3.20 | head -6

From your own workstation, the same push works with Docker or Podman. The registry serves plain HTTP until you add TLS, so Docker clients need the instance listed under insecure-registries in /etc/docker/daemon.json. For Podman, add an [[registry]] entry with insecure = true in /etc/containers/registries.conf:

docker login <vm-ip>
# user admin, password from /root/quay-credentials.txt
docker tag myapp:latest <vm-ip>/admin/myapp:latest
docker push <vm-ip>/admin/myapp:latest

In the web UI, the repository appears immediately, with the tag list showing size, modification time and manifest digest.

Under Organizations, you can create shared namespaces with teams, role-based permissions and robot accounts for CI/CD pipelines.

Step 8 - Use the REST API

Project Quay exposes a complete REST API under /api/v1/. The access token from /root/quay-credentials.txt carries administrative scopes. Read the token into a shell variable and query your user:

TOKEN=$(sudo grep '^QUAY_ACCESS_TOKEN=' /root/quay-credentials.txt | cut -d= -f2-)
curl -s -H "Authorization: Bearer $TOKEN" http://localhost/api/v1/user/ | head -c 200
TOKEN=$(sudo grep '^QUAY_ACCESS_TOKEN=' /root/quay-credentials.txt | cut -d= -f2-)
curl -s -H "Authorization: Bearer $TOKEN" 'http://localhost/api/v1/repository?namespace=admin'

You can create additional application tokens in the web UI under your account settings. Create robot accounts (machine credentials scoped to specific repositories) under each organization.

Step 9 - Enable HTTPS with your own domain

Project Quay ships on plain HTTP on port 80 so it works immediately. For production, point a DNS record at the VM's public IP and terminate TLS in front of the registry.

A common approach is to obtain a certificate with certbot and configure the fronting nginx site (/etc/nginx/sites-available/quay) for TLS. You can also place Azure Application Gateway in front of the VM.

After enabling TLS, update the application's canonical address in /opt/quay/conf/stack/config.yaml. Set SERVER_HOSTNAME to your domain and PREFERRED_URL_SCHEME to https, then restart:

$
sudo systemctl restart quay

With TLS in place, Docker and Podman clients no longer need the insecure registry configuration.

Administration and support

  • Configuration: the application configuration lives in /opt/quay/conf/stack/config.yaml (owned by root and readable by the quay service user).
  • Storage: registry blobs live under /var/lib/quay/storage. Size the OS disk or attach a data disk to match your image volume.
  • Service control and logs: the process tree is managed as one unit with sudo systemctl restart quay, and its logs stream to the journal with sudo journalctl -u quay -f.
  • Worker counts: tune the web, registry and security scanning worker counts through the WORKER_COUNT_* environment variables in /etc/systemd/system/quay.service. They are the same variables the upstream container supports.
  • Swap: quay-swap.service provisions swap on the Azure ephemeral resource disk at every boot. It degrades gracefully on VM sizes without a resource disk.
  • Corporate CA certificates: to add trusted CA certificates for outbound TLS, use Ubuntu's standard flow. Copy the certificate to /usr/local/share/ca-certificates/ and run sudo update-ca-certificates.

This image is a repackaged open source software product with additional charges for SecureAnyCloud support services. Our engineers provide 24/7 support for deployment, upgrades, TLS termination, storage scaling, mirroring configuration and CI/CD integration.

This image is an independent build of the upstream Project Quay open source software (Apache License 2.0). It is not affiliated with, sponsored or endorsed by Red Hat. Quay is a trademark of Red Hat, Inc. All product and company names are trademarks or registered trademarks of their respective holders. The names are used here only to identify the software this image packages.

Deploy on Azure

Launch Project Quay 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

Deploy on Azure