Deployment guide

Apicurio Registry

Overview

Apicurio Registry is an open source runtime registry and datastore for API definitions and event schemas. It stores and serves Avro, Protobuf, JSON Schema, OpenAPI, AsyncAPI, GraphQL and WSDL artifacts through a REST API, a Confluent-compatible Schema Registry API and a React web interface. Producers and consumers across your event streaming and API estate can share a single source of truth for their data contracts.

The SecureAnyCloud image runs the official Quarkus backend under a JDK 21 runtime, with local PostgreSQL storage, under systemd. Apicurio has no built-in authentication in this configuration, so the backend is bound to loopback and never exposed directly. It listens on 127.0.0.1:8080 for the UI and REST API and on 127.0.0.1:9000 for the Quarkus management interface.

An nginx reverse proxy on port 80 serves the official prebuilt web UI and proxies the REST API. It adds a per-VM HTTP Basic Auth gate (user admin, with a unique password generated on first boot) in front of the whole surface. It also serves an unauthenticated /healthz endpoint for load balancer probes. A set of example schemas is registered on first boot, so the browsing UI is populated out of the box.

What you get:

  • Apicurio Registry 3.2.6 running the official Quarkus backend under a JDK 21 runtime as the apicurio systemd service.
  • Local PostgreSQL storage for durable persistence of every group, artifact and version.
  • The official prebuilt React web UI and the REST API on :80, fronted by nginx with the backend bound to loopback only.
  • Per-VM HTTP Basic Auth (user admin) that protects the UI and API, with a unique password generated on first boot.
  • The core Apicurio REST API at /apis/registry/v3 and the Confluent-compatible Schema Registry API at /apis/ccompat/v7.
  • Three example schemas registered on first boot, so the UI is populated immediately.
  • An unauthenticated /healthz endpoint for Azure Load Balancer health probes.
  • apicurio.service, nginx.service and postgresql.service as systemd units, enabled and active.
  • The bcrypt Basic Auth hash is stored on disk only. The PostgreSQL password is rotated and the database is recreated fresh on first boot, so no usable credential ships in the image.
  • 24/7 SecureAnyCloud support.

Prerequisites

  • An active Azure subscription.
  • An SSH key pair.
  • A VNet and a subnet in the target region.
  • Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point. Raise the size for heavy schema traffic.
  • NSG inbound rules that allow 22/tcp from your management network, 80/tcp for the web UI and API, and 443/tcp if you add TLS.

Apicurio serves plain HTTP on port 80. For production, terminate TLS in front of it with your own domain and restrict access to trusted IP ranges (see Maintenance).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal and choose Create a resource. Search the Marketplace for Apicurio Registry by SecureAnyCloud and select Create.

On the Basics tab, 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, and then Create.

Step 2 - Deploy from the Azure CLI

Accept the Marketplace terms and create the virtual machine. Replace the value in angle brackets with your resource group name.

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:apicurio-registry-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name apicurio \
  --image sac1647283583153:apicurio-registry-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Open port 80 for the web UI and API:

az vm open-port --resource-group <your-rg> --name apicurio --port 80

Step 3 - Connect to your VM

Connect to the VM over SSH:

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

Check that the three services are active:

systemctl is-active apicurio.service nginx.service postgresql.service

All three report active. The Apicurio backend serves its UI and REST API on the loopback address 127.0.0.1:8080 and its management interface on 127.0.0.1:9000. nginx fronts it on port 80 and adds the per-VM HTTP Basic Auth gate. The backend is never bound to a public interface, so nginx is the only way in.

Step 5 - Retrieve your web UI password

nginx protects the whole Apicurio surface with HTTP Basic Auth. The username is admin. A unique password is generated on the first boot of your VM and written to a root-only file. Read the file:

sudo cat /root/apicurio-credentials.txt

This file contains APICURIO_USERNAME, APICURIO_PASSWORD and the APICURIO_URL to open in a browser, along with the local PostgreSQL credentials. The web UI password is stored on disk only as a bcrypt hash in /etc/nginx/.apicurio.htpasswd, so no plaintext password ships in the image. Store the password in a safe place.

Step 6 - Confirm the health and readiness endpoints

nginx serves an unauthenticated health endpoint for load balancers and probes. The Quarkus management interface reports readiness on loopback. Query both endpoints:

curl -s http://localhost/healthz
curl -s http://127.0.0.1:9000/health/ready

/healthz returns ok, and the readiness endpoint reports "status":"UP". The /healthz endpoint never requires authentication, so it is safe to use for an Azure Load Balancer health probe.

Step 7 - Confirm authentication

Because a password is set on first boot, an unauthenticated request to the UI or API returns HTTP 401. Nobody reaches the registry without the password.

The following commands read the per-VM password from the credentials file and prove the round trip. An unauthenticated request is rejected, a wrong password is rejected, and the correct password authenticates:

PW=$(sudo grep '^APICURIO_PASSWORD=' /root/apicurio-credentials.txt | cut -d= -f2-)
echo "unauth : $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/)"
echo "wrongpw : $(curl -s -o /dev/null -w '%{http_code}' -u admin:wrong-pw http://127.0.0.1/)"
echo "authed : $(curl -s -o /dev/null -w '%{http_code}' -u admin:$PW http://127.0.0.1/)"

The output is unauth : 401, wrongpw : 401 and authed : 200. The whole surface is reachable only with the per-VM password, because the backend is bound to loopback and nginx is the only way in.

Step 8 - List and fetch schemas with the core REST API

The core Apicurio REST API is at /apis/registry/v3. The image registers three example schemas in the default group on first boot. List the schemas and fetch one back:

PW=$(sudo grep '^APICURIO_PASSWORD=' /root/apicurio-credentials.txt | cut -d= -f2-)
curl -s -u "admin:$PW" http://127.0.0.1/apis/registry/v3/groups/default/artifacts
curl -s -u "admin:$PW" \
  "http://127.0.0.1/apis/registry/v3/groups/default/artifacts/user-signup/versions/branch=latest/content"

The first call lists user-signup (JSON Schema), payment-received (Avro) and order-placed (JSON Schema). The second call returns the JSON Schema content of the latest version of user-signup.

Your applications, CI pipelines and the apicurio-registry client libraries use the same REST API to publish and resolve schemas.

Step 9 - Register a schema with the Confluent compatible API

Apicurio also exposes a Confluent-compatible Schema Registry API at /apis/ccompat/v7. Tools and clients that speak the Confluent Schema Registry protocol work unchanged. Point them at the registry URL with the Basic Auth credentials.

Register an Avro schema under a subject and read it back:

PW=$(sudo grep '^APICURIO_PASSWORD=' /root/apicurio-credentials.txt | cut -d= -f2-)
curl -s -u "admin:$PW" -X POST \
  http://127.0.0.1/apis/ccompat/v7/subjects/orders-value/versions \
  -H 'Content-Type: application/vnd.schemaregistry.v1+json' \
  -d '{"schemaType":"AVRO","schema":"{\"type\":\"record\",\"name\":\"Order\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"}]}"}'
curl -s -u "admin:$PW" http://127.0.0.1/apis/ccompat/v7/subjects

The POST returns the assigned schema id, and the subject appears in the subject list. A Kafka producer or consumer configured with schema.registry.url uses the same endpoint.

Step 10 - Sign in and browse the artifacts

Open http://<vm-public-ip>/ in a browser. The browser prompts for the HTTP Basic Auth credentials. Enter admin and the password from Step 5. The Apicurio Registry Explore view opens. Open the default group to see the three example schemas registered on first boot, each with its type and description.

Step 11 - Open an artifact and review its versions

Select an artifact, for example user-signup, to open its detail view. The Overview tab shows the artifact metadata (name, description, type and timestamps) next to the list of versions. Each artifact can hold many versions. You can create, compare and manage them from here.

Step 12 - View the schema content

Open a version and select the Content tab to view the schema in a syntax-highlighted editor. The editor has a Download button and a JSON or YAML toggle. This is the exact content that your producers and consumers resolve at runtime.

Step 13 - Configure global content rules

The Global rules page lets you enforce governance across the registry. Enable the Validity rule to ensure that content is valid when an artifact or version is created. Enable the Compatibility rule to enforce a compatibility level such as Backward for safe schema evolution. Enable the Integrity rule to enforce reference integrity.

You can also set rules per artifact from the artifact's Rules tab.

Maintenance

Service management. The registry runs as apicurio.service, PostgreSQL as postgresql.service and the reverse proxy as nginx.service. Restart the registry with sudo systemctl restart apicurio. View the logs with sudo journalctl -u apicurio -f.

Add TLS and a domain. For production, put your own domain in front and terminate TLS. Point DNS at the VM. Then either add a certbot managed certificate to nginx, or place the VM behind an Azure Application Gateway or Front Door that terminates HTTPS. Keep the backend bound to loopback and keep nginx as the only public listener.

Rotate the web UI password. Generate a new bcrypt entry for user admin and reload nginx:

NEWPW=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 24) printf '%s\n' "$NEWPW" | sudo htpasswd -iB /etc/nginx/.apicurio.htpasswd admin
sudo systemctl reload nginx echo "new password: $NEWPW"

Back up your schemas. All groups, artifacts and versions live in the local PostgreSQL database apicurio. Take a logical backup with sudo -u postgres pg_dump apicurio > apicurio-backup.sql. Restore it into a fresh database when needed.

Scale the JVM. On first boot, the heap is sized to half of the VM memory, clamped between 512 MB and 1024 MB. For a larger VM, override APICURIO_JAVA_OPTS in /etc/apicurio/apicurio.env and restart the service.

Support

This image is backed by 24/7 SecureAnyCloud support.

Apicurio is a trademark of Red Hat, Inc. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.

Deploy on Azure

Launch Apicurio Registry 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