chproxy for ClickHouse on Ubuntu 24.04 on Azure User Guide
Overview
This image runs chproxy, the open source HTTP proxy and load balancer for ClickHouse, in front of a bundled local ClickHouse server. chproxy is a single Go binary, licensed under the MIT licence, that terminates client HTTP requests, enforces its own user based access control and per user limits, spreads queries across ClickHouse nodes, and can cache responses. ClickHouse itself is licensed under Apache 2.0. Together they give you a working, authenticated ClickHouse HTTP endpoint on one virtual machine, with no vendor lock in or licence ambiguity for commercial deployments.
The chproxy binary is installed at /usr/local/bin/chproxy and runs as a dedicated unprivileged chproxy system account under a systemd service that starts it on boot and restarts it on failure. Its configuration lives at /etc/chproxy/config.yml. chproxy listens for client HTTP requests on TCP port 9090. The bundled ClickHouse server listens on the loopback interface only (127.0.0.1 ports 8123 HTTP and 9000 native) and is never exposed directly; every request reaches it through chproxy.
The image is secure by default. There is no shared bootstrap credential. On the first boot of every deployed virtual machine, a unique chproxy client password and a unique ClickHouse default user password are generated, so two machines launched from the same image never share a credential. The credentials are written to /root/chproxy-credentials.txt with mode 0600 so that only the root user can read them. A request to chproxy with no credentials, or with the wrong password, is refused with HTTP 401; only the per instance client credentials are accepted. The ClickHouse default user rejects its upstream empty password default. The recommended Network Security Group opens SSH alone, so the proxy is not reachable from the internet until you deliberately add a scoped inbound rule or connect over an SSH tunnel.
Prerequisites
Before you deploy this image you need:
- An active Azure subscription with permission to subscribe to Marketplace images and create virtual machines.
- An SSH public key for administrative access.
- A virtual network and subnet in your target region, and a Network Security Group that allows inbound TCP 22 (SSH) from your administrative address. The proxy port 9090 is not exposed by default.
Recommended virtual machine size: Standard_D2s_v5 (2 vCPU, 8 GB RAM) for a small single node deployment. ClickHouse is memory hungry, so choose a larger memory optimised size for production analytics workloads.
Step 1: Deploy from the Azure Portal
- Search for chproxy in the Azure Marketplace, select the cloudimg publisher, and choose Create.
- Select your subscription, resource group and region, and choose the recommended VM size.
- Provide your SSH public key for the
azureuseradministrative account. - Configure the Network Security Group to allow inbound TCP 22 for administration from your address. Leave the proxy port 9090 closed for now; you will open it deliberately for your own clients later if you need direct access.
- Review and create the virtual machine, then note its public IP address.
Step 2: Deploy from the Azure CLI
You can also deploy the image from the command line. Replace the subscription id, image version, and networking with your own:
RG="chproxy-prod"; LOCATION="eastus"; VM_NAME="chproxy1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/chproxy-ubuntu-24-04/versions/latest"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_D2s_v5 \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1001
Step 3: Connect to Your Virtual Machine
Connect over SSH as the azureuser administrative account, using the private key that matches the public key you supplied at deploy time:
ssh -i ~/.ssh/id_rsa azureuser@<public-ip>
Step 4: Retrieve Your Credentials
The per instance credentials are generated on first boot and written to a root only file. Read them with sudo:
sudo cat /root/chproxy-credentials.txt
The file contains the CHPROXY_USERNAME and CHPROXY_PASSWORD values that clients use to authenticate to chproxy, and the CLICKHOUSE_PASSWORD for the bundled ClickHouse default user, all unique to this virtual machine, along with the proxy endpoint and a usage example. Keep these credentials safe.
Step 5: Confirm the Services Are Running
Check that both services are active, confirm the chproxy version, and confirm chproxy is listening on port 9090 as the unprivileged chproxy user while ClickHouse listens on loopback only:
systemctl is-active chproxy.service clickhouse-server.service
/usr/local/bin/chproxy -version
sudo ss -tlnp | grep -E ':9090|:8123'
ps -o user=,comm= -C chproxy
You should see active for both services, the chproxy version, a listener on *:9090 (chproxy) and a 127.0.0.1:8123 listener (ClickHouse, loopback only), and the chproxy process owned by the chproxy account rather than root.

Step 6: Verify Authentication Is Enforced and Run a Query
chproxy is not an open endpoint: a request with no credentials and a request with the wrong password are both refused with HTTP 401, while your per instance credentials succeed and the query is proxied to the bundled ClickHouse. On the virtual machine, read the username and password from the root only credentials file into shell variables (so the secret is never typed on the command line) and pass them to curl:
U=$(sudo grep '^CHPROXY_USERNAME=' /root/chproxy-credentials.txt | cut -d= -f2-)
P=$(sudo grep '^CHPROXY_PASSWORD=' /root/chproxy-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'no credentials -> HTTP %{http_code}\n' 'http://127.0.0.1:9090/?query=SELECT+1'
curl -s -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' "http://$U:wrongpassword@127.0.0.1:9090/?query=SELECT+1"
echo -n 'authenticated -> '; curl -s "http://$U:$P@127.0.0.1:9090/?query=SELECT+version()"
The first two requests return HTTP 401, confirming that no query is forwarded without valid credentials. The authenticated request returns the ClickHouse version string, proving the query was proxied through chproxy to the bundled ClickHouse and answered.

Step 7: Run Real ClickHouse Queries Through the Proxy
Everything ClickHouse's HTTP interface supports works through chproxy. Create a table, insert rows, and read them back, all through the authenticated proxy endpoint:
U=$(sudo grep '^CHPROXY_USERNAME=' /root/chproxy-credentials.txt | cut -d= -f2-)
P=$(sudo grep '^CHPROXY_PASSWORD=' /root/chproxy-credentials.txt | cut -d= -f2-)
CH="http://$U:$P@127.0.0.1:9090/"
curl -s "$CH" --data-binary 'CREATE TABLE IF NOT EXISTS demo (id UInt32, name String) ENGINE = MergeTree ORDER BY id'
curl -s "$CH" --data-binary "INSERT INTO demo VALUES (1,'alpha'),(2,'beta'),(3,'gamma')"
curl -s "$CH?query=SELECT%20count()%20FROM%20demo"
curl -s "$CH" --data-binary 'SELECT id, name FROM demo ORDER BY id FORMAT TabSeparated'
curl -s "$CH" --data-binary 'DROP TABLE demo'
The count returns 3 and the select returns the three rows, confirming end to end reads and writes against ClickHouse through chproxy.

Step 8: Remote Access over an SSH Tunnel
The proxy port is not exposed by the recommended Network Security Group. The simplest way to reach chproxy from your workstation is an SSH tunnel that forwards a local port to port 9090 on the virtual machine:
ssh -i ~/.ssh/id_rsa -L 9090:127.0.0.1:9090 azureuser@<public-ip>
With that tunnel open, point any ClickHouse HTTP client or curl at http://127.0.0.1:9090 on your workstation and authenticate with the per instance chproxy username and password, for example curl "http://CHPROXY_USERNAME:CHPROXY_PASSWORD@127.0.0.1:9090/?query=SELECT+1".
Step 9: Allow Remote Clients Directly (Optional)
If you prefer to reach chproxy directly rather than over a tunnel, do both of the following:
- Add an inbound rule to the virtual machine's Network Security Group allowing TCP 9090 from your own client source range only:
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 9090 --priority 1002 \
--source-address-prefixes <your-mgmt-cidr>
- Widen chproxy's allowed client networks to include that range. Edit
/etc/chproxy/config.yml, add your CIDR underserver->http->allowed_networks, then reload the service:
sudo systemctl reload chproxy
Keep both the Network Security Group rule and the allowed_networks list scoped to the smallest client range you need. The default policy accepts loopback and private (RFC1918) ranges only.
Step 10: Review the Security Policy
The shipped configuration is secure by default. You can review it at any time:
sudo sed -n '1,40p' /etc/chproxy/config.yml
Key controls in the configuration:
- Authentication required — clients must authenticate as the in proxy user defined in the config. There is no
defaultproxy user, so an unauthenticated request maps to a non existent user and is rejected with HTTP 401. - Allowed networks — chproxy accepts client connections from loopback and private (RFC1918) ranges only.
- ClickHouse on loopback — the bundled ClickHouse server listens on 127.0.0.1 only, so it is reachable exclusively through chproxy; its default user has a per instance password and rejects the upstream empty password default.

The credentials are stored safely: the plaintext file is root only (mode 0600), and the ClickHouse default user password is stored as a SHA256 hash in /etc/clickhouse-server/users.xml rather than in plaintext.
Step 11: Service Maintenance
Both services run under systemd. Common operations:
systemctl status chproxy.service --no-pager
sudo systemctl restart chproxy.service
sudo journalctl -u chproxy.service --no-pager -n 50
sudo systemctl status clickhouse-server.service --no-pager
After editing the chproxy configuration, reload the service to apply it:
sudo systemctl reload chproxy.service
Support
cloudimg provides 24/7 technical support for this image by email at support@cloudimg.co.uk and via live chat. We assist with deployment and machine sizing, chproxy user and cluster configuration, ClickHouse tuning, client access list changes, response caching, credential management, and performance troubleshooting. Please include your Azure virtual machine name and a description of the issue for fastest routing.