CockroachDB 25.4 Core on Ubuntu 22.04 on Azure User Guide
Overview
This image runs CockroachDB 25.4 Core as a single node distributed SQL database on Ubuntu 22.04 LTS. CockroachDB is the cloud native distributed SQL database from Cockroach Labs, licensed under the Business Source License which converts to Apache 2.0 three years after each release. Running CockroachDB Core on a virtual machine that you deploy and manage yourself is a permitted use under the Business Source License.
CockroachDB is wire compatible with PostgreSQL. Clients that speak the PostgreSQL wire protocol, including the psql command line client, every JDBC or ODBC driver, every ORM that targets PostgreSQL, and the pgAdmin web UI, talk to CockroachDB unchanged. The SQL grammar is largely a superset of standard SQL and includes native UUID, JSONB, ARRAY, TIMESTAMPTZ, and geospatial types. The storage engine is a Raft replicated key value store with strong consistency guarantees, which is why CockroachDB scales horizontally by adding nodes rather than by sharding at the application layer.
This image ships CockroachDB configured in secure mode with a unique self signed certificate authority generated on the very first boot of every deployed virtual machine. A root client certificate, a node certificate, and a certificate authority certificate are all written to /var/lib/cockroach/certs under a cockroach system user. A SQL user named cloudimg is provisioned with a randomly generated password, granted the built in admin role, and the password is written to a single root only file at /stage/scripts/cockroachdb-credentials.log. A default database named cloudimg_demo is created ready for your first query. Two virtual machines launched from the same gallery image never share certificates, never share passwords, and do not trust each other's certificate authorities.
The SQL and gRPC port is 26257, the same port the PostgreSQL wire protocol listens on. The DB Console web UI, which presents the cluster dashboard, SQL activity, jobs, and metrics, listens on 8080 over HTTPS and uses the node certificate for TLS. You log into the DB Console as the cloudimg user with the generated password. There is no embedded load balancer and no separate coordinator process; the cockroach binary is a single statically compiled Go executable with no Java, no Python, and no other embedded runtime, which means the image has zero runtime CVE surface from bundled virtual machines or interpreters.
The image is intended for teams that want a production posture single node SQL database on day one for development, testing, and small production workloads, with a clear upgrade path to multi node by joining additional cockroach nodes to the cluster later. It is not a replicated multi node cluster out of the box, the self signed certificate authority is not trusted by browsers or OS certificate stores, and the DB Console is not exposed on a CA signed TLS chain. Section 18 covers replacing the certificates with a properly signed chain and the security posture you want before placing customer data on the server.
The brand is lowercase cloudimg throughout this guide. All cloudimg URLs in this guide use the form https://www.cloudimg.co.uk.
Prerequisites
Before you deploy this image you need:
- A Microsoft Azure subscription where you can create resource groups, virtual networks, and virtual machines
- Azure role permissions equivalent to Contributor on the target resource group
- An SSH public key for first login to the admin user account
- A virtual network and subnet in the same region as the Azure Compute Gallery the image is published into, with an associated network security group
- The Azure CLI (
azversion 2.50 or later) installed locally if you intend to use the CLI deployment path in Section 2 - The cloudimg CockroachDB 25.4 offer enabled on your tenant in Azure Marketplace
Step 1: Deploy the Virtual Machine from the Azure Portal
Navigate to Marketplace in the Azure Portal, search for CockroachDB 25.4, and select the cloudimg publisher entry. Click Create to begin the wizard.
On the Basics tab choose your subscription, target resource group, and region. The region must match the region your Azure Compute Gallery exposes the image in. Set the virtual machine name. Choose SSH public key as the authentication type, set the username to a name of your choice, and paste your SSH public key. Standard_D2s_v3 is the recommended starting size because CockroachDB keeps its write ahead buffer and block cache in memory and benefits from 8 gigabytes of RAM on a single node deployment. Scale up to Standard_D4s_v3 or Standard_D8s_v3 for busier write workloads or larger working sets.
On the Disks tab the recommended OS disk type is Standard SSD. The CockroachDB data directory lives at /var/lib/cockroach/cockroach-data. If you expect to store more than a few gigabytes of data, attach a separate Premium SSD data disk now and follow Section 17 after the server is running to move the data directory across.
On the Networking tab select your existing virtual network and subnet. Attach a network security group that allows inbound TCP 22 from your management IP range, inbound TCP 26257 only from the application subnets that need to run SQL, and inbound TCP 8080 only from the management IP range you use to open the DB Console. Do not expose 26257 or 8080 to the public internet. Network level isolation is the first line of defence; the cockroach server enforces TLS and password authentication on top of that.
On the Management, Monitoring, and Advanced tabs the defaults are appropriate. Click Review + create, wait for validation to pass, then click Create. Deployment takes around two minutes.
Step 2: Deploy the Virtual Machine from the Azure CLI
If you prefer the command line, use the gallery image resource identifier as the source. The exact resource identifier is published on your Partner Center plan. A representative invocation:
RG="cockroachdb-prod"
LOCATION="eastus"
VM_NAME="cockroachdb-01"
ADMIN_USER="cockroach-admin"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/cockroachdb-25-4-ubuntu-22-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create \
--resource-group "$RG" \
--name cockroachdb-vnet \
--address-prefix 10.50.0.0/16 \
--subnet-name cockroachdb-subnet \
--subnet-prefix 10.50.1.0/24
az network nsg create --resource-group "$RG" --name cockroachdb-nsg
az network nsg rule create \
--resource-group "$RG" --nsg-name cockroachdb-nsg \
--name allow-ssh-mgmt --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" \
--destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create \
--resource-group "$RG" --nsg-name cockroachdb-nsg \
--name allow-sql-vnet --priority 110 \
--source-address-prefixes 10.50.0.0/16 \
--destination-port-ranges 26257 --access Allow --protocol Tcp
az network nsg rule create \
--resource-group "$RG" --nsg-name cockroachdb-nsg \
--name allow-db-console-mgmt --priority 120 \
--source-address-prefixes "<your-mgmt-cidr>" \
--destination-port-ranges 8080 --access Allow --protocol Tcp
az vm create \
--resource-group "$RG" \
--name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_D2s_v3 \
--storage-sku StandardSSD_LRS \
--admin-username "$ADMIN_USER" \
--ssh-key-values "$SSH_KEY" \
--vnet-name cockroachdb-vnet --subnet cockroachdb-subnet \
--nsg cockroachdb-nsg \
--public-ip-address "" \
--os-disk-size-gb 32
The --public-ip-address "" flag keeps the server off the public internet. Use a bastion host or your existing private connectivity to reach it.
Step 3: Connect via SSH
After deployment, find the private IP of the new virtual machine. From a host inside the same virtual network:
ssh cockroach-admin@<vm-ip>
Substitute the username you chose at deployment time and the private IP the Azure portal or CLI returned.
Step 4: Retrieve the Admin Credentials
On the first boot of every deployed virtual machine, the cockroach-firstboot.service generates a unique password for the cloudimg SQL user and writes it to a root only file. Read it once and store it somewhere safe.
sudo cat /stage/scripts/cockroachdb-credentials.log
The file documents the SQL port, the DB Console port, the admin user name, the admin password, the certificates directory, and three sample connection strings. The password is shown in plain text only in this file. Rotate the password with the ALTER USER statement covered in Section 14 whenever you need to.
Step 5: Connect via cockroach sql
The cockroach CLI authenticates to the server using the pre generated root client certificate under /var/lib/cockroach/certs. No password is required when you invoke it on the VM as root or with sudo.
sudo /usr/local/bin/cockroach sql \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257 \
-e "SELECT version();"
The response is a single row containing the CockroachDB version banner, for example CockroachDB CCL v25.4.8 (x86_64-pc-linux-gnu, ...).
You can open an interactive shell the same way without the -e flag:
sudo /usr/local/bin/cockroach sql \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257
Exit the shell with \q or Ctrl-D.
Step 6: Connect via psql to Prove PostgreSQL Wire Compatibility
CockroachDB speaks the PostgreSQL wire protocol on port 26257. The psql client, installed as part of the postgresql-client-14 package on this image, connects to it with a standard PostgreSQL connection string. TLS is mandatory because the server runs in secure mode; sslmode=require is the right choice for the self signed certificate authority this image ships with. For production, generate a proper CA chain and use sslmode=verify-full.
export ADMIN_PASSWORD="$(sudo awk -F= '/^admin_password=/ {print $2}' /stage/scripts/cockroachdb-credentials.log)"
PGPASSWORD="$ADMIN_PASSWORD" psql \
"host=localhost port=26257 user=cloudimg dbname=cloudimg_demo sslmode=require" \
-c "SELECT version();"
The psql output is the CockroachDB version banner, confirming that PostgreSQL clients see the same identity as the cockroach CLI. Any tool that targets PostgreSQL, including every JDBC driver, every ORM, and pgAdmin, connects the same way.
Step 7: Open the DB Console
The DB Console is CockroachDB's built in web UI for the cluster dashboard, SQL activity, jobs, and metrics. It listens on port 8080 over HTTPS and is presented by the node certificate. On a freshly deployed VM the certificate is self signed, so your browser will warn about the authority; accept the warning for a development workflow or, for production, replace the certificate with a CA signed chain as covered in Section 18.
Open the DB Console at:
https://<vm-ip>:8080
Log in as the cloudimg user with the password from the credentials file. The overview page shows the single node cluster state, capacity utilisation, range counts, and live query metrics.
Step 8: Create a Table and Run a SQL Query
From a cockroach sql shell against the cloudimg_demo database, create a table with a JSONB column, insert a row, and run a query that exercises CockroachDB's SQL optimiser.
sudo /usr/local/bin/cockroach sql \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257 \
--database=cloudimg_demo <<'SQL'
CREATE TABLE IF NOT EXISTS events (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
ts TIMESTAMPTZ DEFAULT now(),
data JSONB
);
INSERT INTO events (data) VALUES
('{"sensor": "temp", "value": 23.5}'),
('{"sensor": "humidity", "value": 68}');
SELECT id, ts, data->>'sensor' AS sensor, data->>'value' AS value
FROM events ORDER BY ts DESC;
SQL
The SELECT returns two rows, one per inserted event, with the sensor and value fields extracted from the JSONB column.
Step 9: Server Components
The components installed by this image:
- CockroachDB Core 25.4, pinned at build time, installed from the official signed tarball at binaries.cockroachdb.com
- Binary at /usr/local/bin/cockroach (single statically compiled Go binary)
- Shared libraries under /usr/local/lib/cockroach/
- A systemd oneshot cockroach-certs.service that generates a per VM self signed certificate authority on first boot
- A systemd cockroach.service that starts the server in secure mode with the generated certs
- A systemd oneshot cockroach-firstboot.service that generates the cloudimg user password and the cloudimg_demo default database on first boot
The operating system base is Ubuntu 22.04 LTS with kernel security updates scheduled through 2027 and extended support to 2032.
Step 10: Filesystem Layout
Default paths on the image:
- /var/lib/cockroach — root of the cockroach system user home, owned cockroach:cockroach, mode 0750
- /var/lib/cockroach/cockroach-data — the CockroachDB storage engine store
- /var/lib/cockroach/certs — the certs directory consumed by the server, contains ca.crt, node.crt, node.key, client.root.crt, client.root.key
- /var/lib/cockroach/cert-ca — the certificate authority private key, used only by cockroach cert CLI invocations during regeneration
- /var/lib/cockroach/logs — CockroachDB log output
- /etc/cockroach/cockroach.env — the systemd EnvironmentFile for the server, controls store path, bind addresses, cache sizing, certs dir
- /etc/systemd/system/cockroach-certs.service — the cert provisioning unit
- /etc/systemd/system/cockroach.service — the main server unit
- /etc/systemd/system/cockroach-firstboot.service — the password and default database provisioning unit
- /usr/local/sbin/cockroach-certs.sh, cockroach-firstboot.sh, cockroach-start.sh, cockroach-stop.sh, setEnv.sh — cloudimg helper scripts
ls -la /var/lib/cockroach/
ls -la /var/lib/cockroach/certs/
sudo cat /etc/cockroach/cockroach.env
Step 11: Managing the CockroachDB Service
CockroachDB is under systemd control. Status, start, and stop commands use the cockroach unit name.
sudo systemctl status --no-pager cockroach
sudo systemctl restart cockroach
To view the last 100 lines of server logs from the systemd journal:
sudo journalctl -u cockroach -n 100 --no-pager
The CockroachDB node status command from the cockroach CLI shows cluster health, ranges, replicas, and live status from the server's own point of view:
sudo /usr/local/bin/cockroach node status \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257
On a single node deployment this returns a single row showing one live, up to date node.
Step 12: Rotate the Admin Password
Rotate the cloudimg user password whenever you need to, for example after a team member leaves or the credential file has been shared. The cockroach CLI authenticates via its root client certificate, so the rotation does not need the old password.
NEW_PASSWORD="$(openssl rand -base64 32 | tr -dc 'A-Za-z0-9' | head -c 24)"
sudo /usr/local/bin/cockroach sql \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257 \
-e "ALTER USER cloudimg WITH PASSWORD '$NEW_PASSWORD';"
echo "New password: $NEW_PASSWORD"
Record the new password in your secrets store and update any clients that connect as the cloudimg user. The credentials file at /stage/scripts/cockroachdb-credentials.log is the provisioning value; after rotation it is out of date and should be deleted or updated.
Step 13: Create Application Users
Production applications should never authenticate as the cloudimg admin user. Create one role per application, grant only the privileges that application needs, and hand that application its own password. Root access via the client certificate stays on the server for administrative work.
APP_PASSWORD="$(openssl rand -base64 32 | tr -dc 'A-Za-z0-9' | head -c 24)"
sudo /usr/local/bin/cockroach sql \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257 <<SQL
CREATE USER IF NOT EXISTS app_reader WITH PASSWORD '$APP_PASSWORD';
GRANT CONNECT ON DATABASE cloudimg_demo TO app_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA cloudimg_demo.public TO app_reader;
SQL
echo "app_reader password: $APP_PASSWORD"
Grant INSERT, UPDATE, DELETE, and DDL privileges only where an application actually needs them. See the CockroachDB documentation at https://www.cockroachlabs.com/docs/v25.4/security-reference/authorization for the full privilege matrix.
Step 14: Reconfigure at Runtime with systemd Drop-In Overrides
Any runtime option controlled by the systemd unit (resource limits, restart policy, the User= directive) should be changed via a systemd drop-in rather than by editing the unit file in place. A drop-in survives package upgrades and is the systemd recommended pattern.
sudo systemctl edit cockroach
The editor opens an empty override file under /etc/systemd/system/cockroach.service.d/override.conf. A sample override that bumps the file descriptor limit and the start timeout:
[Service]
LimitNOFILE=131072
TimeoutStartSec=240
Save and exit. Reload the systemd daemon and restart the service to apply.
sudo systemctl daemon-reload
sudo systemctl restart cockroach
Runtime options that the cockroach binary itself controls, such as the cache size or the SQL memory budget, live in /etc/cockroach/cockroach.env. Edit that file and restart the service to apply.
Step 15: Back Up and Restore
CockroachDB includes a built in logical backup and restore mechanism. The simplest path on a single node deployment is to dump the database with the cockroach CLI and store the dump outside the VM.
sudo /usr/local/bin/cockroach sql \
--certs-dir=/var/lib/cockroach/certs \
--host=localhost:26257 \
--database=cloudimg_demo \
--format=sql \
-e "SELECT * FROM events" > /tmp/events-dump.sql
ls -la /tmp/events-dump.sql
Copy the dump to an external location (Azure Blob Storage, SFTP, or your backup system) and store it for the retention window your organisation requires. For multi node clusters the BACKUP TO ... SQL statement writes a cluster backup to Azure Blob Storage or another supported object store; see https://www.cockroachlabs.com/docs/v25.4/take-full-and-incremental-backups for the syntax.
Step 16: Connect from an Application
Any PostgreSQL client library works with CockroachDB. Use a connection string in the form postgresql://<user>:<password>@<host>:26257/<database>?sslmode=require. From Python with psycopg2, for example:
pip install psycopg2-binary
python3 - <<'PY'
import os, psycopg2
conn = psycopg2.connect(
host="localhost",
port=26257,
user="cloudimg",
password=os.environ["ADMIN_PASSWORD"],
dbname="cloudimg_demo",
sslmode="require",
)
cur = conn.cursor()
cur.execute("SELECT count(*) FROM events;")
print("event count:", cur.fetchone()[0])
conn.close()
PY
Substitute your application's language and driver as needed; the connection string format is the same.
Step 17: Move Data to an Attached Disk
If you attached a separate data disk at deployment time, move the CockroachDB store there before ingesting production data. The default store at /var/lib/cockroach/cockroach-data shares the OS disk, which is usually smaller and less performant than a dedicated Premium SSD. Below is the sequence for a single data disk attached as /dev/sdc.
Stop the server, mount the disk, copy the store, and update the environment file to point at the new location. Do this before you have written any production data to the default store; migration while the database is under load requires backup and restore instead.
sudo systemctl stop cockroach
sudo mkfs.ext4 /dev/sdc
sudo mkdir -p /data/cockroach
sudo mount /dev/sdc /data/cockroach
sudo rsync -a /var/lib/cockroach/cockroach-data/ /data/cockroach/cockroach-data/
sudo chown -R cockroach:cockroach /data/cockroach
Add an entry to /etc/fstab so the disk mounts on boot, then edit /etc/cockroach/cockroach.env to set COCKROACH_STORE=/data/cockroach/cockroach-data and restart the service. Verify with lsblk and sudo /usr/local/bin/cockroach node status.
Step 18: Replace the Self Signed Certificate Authority for Production
The image ships with a self signed certificate authority generated at first boot. That is fine for development and for inside a trusted virtual network, but it is not fine for production. Replace the CA with a properly signed chain from your organisation's certificate authority or a public CA before placing customer data on the server.
The high level sequence, executed as the root user on the VM:
- Stop the service with
sudo systemctl stop cockroach - Generate a new certificate authority private key in your organisation's CA workflow and issue a CA certificate
- Issue a node certificate with subject alternative names covering every DNS name and IP the server will be reached at
- Issue a client certificate for the
rootCockroachDB user - Replace /var/lib/cockroach/certs/ca.crt, /var/lib/cockroach/certs/node.crt, /var/lib/cockroach/certs/node.key, /var/lib/cockroach/certs/client.root.crt, and /var/lib/cockroach/certs/client.root.key with the new artefacts
- Ensure file ownership is cockroach:cockroach and the directory mode is 0700
- Restart the service with
sudo systemctl start cockroach
Detailed walk throughs for enterprise PKI integration live in the CockroachDB documentation at https://www.cockroachlabs.com/docs/v25.4/create-security-certificates-openssl. The same section covers rotating certificates without downtime on a multi node cluster.
Step 19: Troubleshooting
If you cannot connect on port 26257, check that the service is running, the port is bound, and the NSG allows traffic from your source.
sudo systemctl is-active cockroach
sudo ss -tln | grep -E ':(26257|8080) '
If systemctl is-active reports failed, the server did not start cleanly. View the journal:
sudo journalctl -u cockroach -n 100 --no-pager
Common failure modes are cert directory permissions (must be 0700, owned cockroach:cockroach) and a mismatched --certs-dir between the unit file and the actual directory.
If the DB Console on 8080 is unreachable from a browser but curl from the VM succeeds, the NSG rule for 8080 is missing or restricted to a CIDR that does not include your browser's source address.
If the cockroach node status command reports the node as not ready, wait thirty seconds after a restart. CockroachDB performs a store scan and range check at startup that takes a few seconds even on a single node cluster.
Step 20: Security Recommendations
For anything beyond development:
- Restrict inbound 26257 on the NSG to the specific application subnets that run SQL; never expose it to the public internet
- Restrict inbound 8080 on the NSG to the management IP range you use to open the DB Console
- Replace the self signed certificate authority with a properly signed chain per Section 18 before placing customer data on the server
- Create per application users with the minimum privileges they need rather than reusing the cloudimg admin account
- Rotate the cloudimg admin password per Section 12 on a schedule that matches your organisation's credential hygiene policy
- Enable Azure Defender for Databases on the resource group for continuous security posture monitoring
- Keep the OS patched; this image ships with unattended-upgrades enabled for Ubuntu Security updates
Step 21: Support and Licensing
Support. cloudimg provides 24/7/365 expert technical support on this image, with a 24 hour guaranteed response time and a one hour average response for critical issues. Contact support@cloudimg.co.uk.
CockroachDB licence. CockroachDB Core is distributed under the Cockroach Community Licence, a form of the Business Source License. Under the BSL you may run CockroachDB on infrastructure you control, including pre configured virtual machine images like this one, with no per core or per seat runtime fee. Three years after each CockroachDB release the license converts to Apache 2.0. The cloudimg image ships the unmodified upstream binary; any CockroachDB trademark is the property of Cockroach Labs, Inc.
Ubuntu licence. Ubuntu 22.04 LTS is distributed under the terms published by Canonical at https://ubuntu.com/licensing.
cloudimg charges. The Azure Marketplace listing shows the per core hourly charge for this image. That charge covers cloudimg's build, security maintenance, and support services; it is separate from Azure compute and storage costs, which Azure bills separately.
Visit https://www.cloudimg.co.uk/guides/cockroachdb-25-4-on-ubuntu-22-04-azure for the latest version of this guide.