Posted in

How to Install Red Hat Quay and Secure with Nginx & Let’s Encrypt

In this blog post, I’ll walk you through installing Red Hat Quay using Podman containers, setting up the necessary PostgreSQL and Redis dependencies, and then securing your registry with a reverse proxy (nginx) and Let’s Encrypt SSL certificates behind Cloudflare. This approach provides a production-quality private container registry that’s straightforward to replicate.

You can skip everything and use the docker-compose file at the end of this blog post. 🙂

1. Create a Custom Network

First, ensure you have a dedicated Podman network (here called test) for seamless container communication.

sudo podman network create test

2. Start the PostgreSQL Database

Quay relies on a PostgreSQL database. Start one with the following, customizing passwords as needed. If you’re using RHEL, CentOS, Fedora, you will likely need the command below to define the permissions required on the directory /docker/postgres-quay.

sudo mkdir -p /docker/postgres-quay
sudo setfacl -m u:26:-wx /docker/postgres-quay
sudo podman run -d --name postgresql-quay --net test \
  -e POSTGRESQL_USER=quayuser1 \
  -e POSTGRESQL_PASSWORD=quaypass1 \
  -e POSTGRESQL_DATABASE=quay \
  -e POSTGRESQL_ADMIN_PASSWORD=adminpass123 \
  -p 5432:5432 \
  -v /docker/postgres-quay:/var/lib/pgsql/data:Z \
  registry.redhat.io/rhel8/postgresql-10:1

Next, enable the pg_trgm extension (required for Quay):

sudo podman exec -it postgresql-quay /bin/bash -c 'echo "CREATE EXTENSION IF NOT EXISTS pg_trgm" | psql -d quay -U postgres'

3. Start the Redis Cache

Quay also uses Redis for caching and background tasks. Launch Redis as below:

sudo podman run -d --name redis --net test \
  -p 6379:6379 \
  -e REDIS_PASSWORD=strongpassword \
  registry.redhat.io/rhel8/redis-5:1

4. Generate Quay Configuration

Before the Quay service itself can run, you need to create a config bundle. Run the Quay container in configuration mode:

sudo podman run --rm -it --name quay_config --net test \
  -p 80:8080 -p 443:8443 \
  -v /docker/quay/config:/conf/stack:Z \
  registry.redhat.io/quay/quay-rhel8:v3.7.8 config secret

Follow the web config prompts in your browser (connect to http://localhost:80 or https://localhost:443 if running locally), set your registry settings, and fill out DB/Redis parameters.

In the web UI, enter the below details before generating the config file

  • Basic configuration
    • Don’t change, use default values.
  • Server configuration
    • enter quay.example.com
  • Database
    • For the purpose of this exercise, enter the below
    • Database Type: Postgres
    • Database Server: postgresql-quay:5432
    • Username: quayuser1
    • Password: quaypass1
    • Database Name: quay
  • Redis
    • Redis Hostname: redis
    • Redis port: 6379 (default)
    • Redis password: strongpassword1

When all required fields have been set, validate your settings by clicking Validate Configuration Changes. If any errors are reported, continue editing your configuration until all required fields are valid and Red Hat Quay can connect to your database and Redis servers.

5. Run the Quay Service

Now launch your Quay service using the generated config and a persistent data path:

sudo podman run -d --stop-timeout=30 -p 80:8080 -p 443:8443 \
  --name=quay --net test \
  -v /docker/quay/config:/conf/stack:Z \
  -v /docker/quay/storage:/datastorage:Z \
  registry.redhat.io/quay/quay-rhel8:v3.7.8

6. OPTIONAL: Using Docker Instead of Podman

If you prefer Docker, the commands are almost identical except for the syntax:

docker run --rm -it --name quay_config --net test \
  -p 80:8080 -p 443:8443 \
  -v /docker/quay/config:/conf/stack:Z \
  registry.redhat.io/quay/quay-rhel8:v3.7.8 config secret

docker run -d --stop-timeout=30 -p 8080:8080 -p 8443:8443 \
  --name=quay --net test \
  -v /docker/quay/config:/conf/stack:Z \
  -v /docker/quay/storage:/datastorage:Z \
  registry.redhat.io/quay/quay-rhel8:v3.7.8

7. Secure With Nginx, Let’s Encrypt, and Cloudflare

By default, Podman/Docker containers may use self-signed certs, prompting browser and CLI warnings. To remedy this:

  1. Set up nginx as a reverse proxy in front of your Quay service.
  2. Use Certbot (Let’s Encrypt) to generate trusted SSL certificates.
  3. Optionally, configure Cloudflare as your DNS proxy for added DNS-layer protection and to streamline SSL management.

Basic example Nginx config snippet:

server {
    listen 443 ssl;
    server_name yourregistry.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourregistry.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourregistry.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

After reloading nginx, your Quay registry should be accessible at https://quay.example.com with a valid SSL certificate—no more invalid cert warnings when using Podman, Docker, or via browsers.

Tip: Always keep your configuration files and storage directories secure and regularly backed up. Consider automating cert renewals with Certbot’s cron setup.

That’s it! You now have a secure, production-ready Quay registry running in containers, backed by PostgreSQL and Redis, and fully protected by SSL via Nginx and Let’s Encrypt behind Cloudflare.

8. Kickstart with docker-compose

I’m going to paste my docker-compose.yml here for easy access infuture.

services:
  nginx-pm:
    container_name: nginx-pm
    image: "jlesage/nginx-proxy-manager:latest"
    restart: unless-stopped
    ports:
      - '443:4443'
    #  - '81:81'
      - '80:8080'
    volumes:
      - "/docker/nginx-pm:/config:rw"
    environment:
      - "USER_ID=xXx"
      - "GROUP_ID=xXx"
      - "TZ=Asia/Singapore"
      - "DISABLE_IPV6=1"
    networks:
      test:

  redis:
    container_name: redis
    image: registry.redhat.io/rhel8/redis-5:1
    environment:
      - REDIS_PASSWORD=strongpassword1
    networks:
      test:

  postgres-quay:
    container_name: postgresql-quay
    image: registry.redhat.io/rhel8/postgresql-10:1
    volumes:
      - /docker/postgres-quay:/var/lib/pgsql/data
    environment:
      - POSTGRESQL_USER=quayuser1
      - POSTGRESQL_PASSWORD=quaypass1
      - POSTGRESQL_DATABASE=quay
      - POSTGRESQL_ADMIN_PASSWORD=adminpass123
    networks:
      test:

  quay:
    container_name: quay
    image: "registry.redhat.io/quay/quay-rhel8:v3.7.8"
    restart: unless-stopped
    #ports:
    # - 8080:8080
    # - 8443:8443
    volumes:
     - /docker/quay/config:/conf/stack:Z
     - /docker/quay/storage:/datastorage:Z
    stop_grace_period: 30s
    networks:
      test:

networks:
  test:
    name: test
    external: true

Leave a Reply

Your email address will not be published. Required fields are marked *