CouchDB 3.5
Overview
Apache CouchDB is a document-oriented NoSQL database. It stores JSON documents, exposes every operation over a RESTful HTTP API, ships with the browser-based Fauxton admin UI, and supports multi-master replication across data centres and offline-first clients.
This SecureAnyCloud image deploys Apache CouchDB 3.5 Core on Ubuntu 22.04 for Microsoft Azure. It is for teams that want a production-posture, single-node CouchDB on day one, without spending hours on packaging, systemd plumbing, admin bootstrap or first database creation.
What you get:
- Apache CouchDB 3.5 with the Erlang VM bundled in the Debian package, so there is no Java runtime and no separate Python dependency on the image
- A single port, 5984, for the HTTP API, the Fauxton admin UI and the replication protocol
- A unique admin password generated per VM on first boot
- A first-boot service and a systemd unit that start CouchDB in the correct order
- 24/7 SecureAnyCloud support
The single-port model is the simplest network exposure of any database image in the SecureAnyCloud catalogue. It is also the biggest security consideration, because exposing port 5984 to the public internet exposes the admin UI as well as the data plane. Step 17 covers the security posture you want before putting customer traffic through the server.
This image is not a clustered deployment across three or more nodes, it is not TLS-encrypted out of the box, and it does not ship with a reverse proxy.
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 deploy from the CLI (Step 2) - The SecureAnyCloud Apache CouchDB 3.5 offer enabled on your tenant in Azure Marketplace
Deploy the Virtual Machine from the Azure Portal
Open Marketplace in the Azure Portal, search for CouchDB, and select the SecureAnyCloud publisher entry. Click Create to begin the wizard.
On the Basics tab, pick your subscription, resource group and region. The region must match the region the Azure Compute Gallery publishes this image into (the default for the SecureAnyCloud offer is East US).
Choose the VM size Standard_B2s. CouchDB on Erlang is lightweight at idle, and customers typically scale by data volume rather than CPU or memory. Create an admin username (the default azureuser is fine) and paste your SSH public key into the authentication section.
On the Disks tab, choose Standard SSD as the OS disk type. The CouchDB data directory lives at /opt/couchdb/data. If you expect your database to grow beyond a few gigabytes, attach a separate Premium SSD data disk now. After the server is running, follow Step 15 to move the data directory across.
On the Networking tab, attach the virtual network and subnet you prepared, and pick an existing NSG or create a new one. Open port 22 for SSH from your management CIDR only. Open port 5984 from the CIDRs that host the applications that will talk to CouchDB.
Do not open port 5984 to the public internet. That port serves the Fauxton admin UI as well as the REST API, so an open 5984 exposes the admin plane.
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.
Deploy the Virtual Machine from the Azure CLI
To deploy from the command line, accept the Marketplace terms once, then create the VM from the Marketplace image URN:
RG="couchdb-prod" LOCATION="eastus" VM_NAME="couchdb-01" ADMIN_USER="azureuser" IMAGE_URN="sac1647283583153:couchdb-3-5-ubuntu-22-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create \
--resource-group "$RG" \
--name couchdb-vnet \
--address-prefix 10.42.0.0/16 \
--subnet-name couchdb-subnet \
--subnet-prefix 10.42.1.0/24 az network nsg create --resource-group "$RG" --name couchdb-nsg az network nsg rule create \
--resource-group "$RG" --nsg-name couchdb-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 couchdb-nsg \
--name allow-couchdb-vnet --priority 110 \
--source-address-prefixes 10.42.0.0/16 \
--destination-port-ranges 5984 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:couchdb-3-5-ubuntu-22-04:default:latest
az vm create \
--resource-group "$RG" \
--name "$VM_NAME" \
--image "$IMAGE_URN" \
--size Standard_B2s \
--storage-sku StandardSSD_LRS \
--admin-username "$ADMIN_USER" \
--ssh-key-values "$SSH_KEY" \
--vnet-name couchdb-vnet --subnet couchdb-subnet --nsg couchdb-nsg \
--public-ip-sku Standard --location "$LOCATION"Connect via SSH
When the VM is running, connect over SSH as the admin user you chose:
ssh azureuser@<vm-ip>Replace <vm-ip> with the public IP address shown in the Azure Portal or returned by az vm show -g "$RG" -n "$VM_NAME" --query publicIps -o tsv.
Retrieve the Admin Password
On first boot, a first-boot service generates a unique admin password for your VM. It writes the password to /opt/couchdb/etc/local.d/10-admins.ini, which CouchDB rewrites as a pbkdf2 hash as soon as the daemon starts. It also writes the plain-text password to /stage/scripts/couchdb-credentials.log with mode 600, root only.
Read the password once, store it in your secrets manager, and export it in the shell for the rest of this guide:
sudo cat /stage/scripts/couchdb-credentials.log export PASSWORD="$(sudo awk -F= '/^password=/ {print $2}' /stage/scripts/couchdb-credentials.log)" echo "admin password length: ${#PASSWORD}"The credentials file also records the default port and a one-line sample_connect command you can copy and paste. Every later bash command in this guide assumes $PASSWORD is exported.
Verify the Server is Healthy
The CouchDB welcome endpoint returns a JSON document that confirms the server is running and reports its version. The _up endpoint is a dedicated health probe. Both require HTTP Basic authentication, because the image ships with require_valid_user = true:
curl -s -u "admin:$PASSWORD" http://localhost:5984/
curl -s -u "admin:$PASSWORD" http://localhost:5984/_upThe welcome response reports "couchdb":"Welcome" and the installed version. The _up response returns {"status":"ok","seeds":{}}.
Server Components
Component Version Source
Apache CouchDB 3.5.x apache.jfrog.io/artifactory/couchdb-deb jammy main
Erlang VM bundled in the CouchDB .deb Apache CouchDB package
Ubuntu 22.04 LTS Azure Marketplace base image
SecureAnyCloud overrides 20-sac.ini baked into the image
CouchDB ships with the Erlang VM statically bundled inside /opt/couchdb, so the image has no system Erlang dependency and no JDK. There is no separate backend database, no message broker and no second port, so there is nothing else to manage.
Filesystem Layout
CouchDB is self-contained under /opt/couchdb. The main directories and files on the image are:
/opt/couchdb/bin/couchdb: the CouchDB launcher script/opt/couchdb/etc/local.ini: the primary configuration file, with the defaults shipped in the package/opt/couchdb/etc/local.d/10-admins.ini: admin credentials (plain text at first boot, hashed after daemon startup)- /opt/couchdb/etc/local.d/20-sac.ini: SecureAnyCloud overrides (port, bind address, auth mode)
/opt/couchdb/etc/vm.args: Erlang VM arguments (node name, cookie)/opt/couchdb/data/: all database files and indexes/opt/couchdb/var/log/couchdb.log: structured log output/stage/scripts/couchdb-credentials.log: the per-VM admin password, mode 600, root only/etc/systemd/system/couchdb.service.d/10-firstboot-order.conf: a systemd drop-in that orders couchdb.service after the first-boot unit
Start, Stop, and Check Status
CouchDB runs as the systemd service couchdb.service. The first-boot unit is couchdb-firstboot.service. It is skipped on every boot after the first, because its ConditionPathExists sentinel lives at /opt/couchdb/data/.firstboot-done.
Manage the main service with systemctl:
sudo systemctl status --no-pager couchdb
sudo systemctl is-active couchdbAfter editing configuration, restart the server:
sudo systemctl restart couchdbThe service runs as the couchdb system user, owns /opt/couchdb, and writes its logs to /opt/couchdb/var/log/couchdb.log.
Open the Fauxton Admin UI
CouchDB ships with Fauxton, a browser-based admin UI that runs on the same port as the REST API, 5984. Make sure port 5984 is open from your management CIDR in the NSG (Step 1 and Step 2). Then open the following URL in your browser:
http://<vm-ip>:5984/_utils/Log in with the admin user and the password from /stage/scripts/couchdb-credentials.log. Fauxton offers database browsing, document editing, Mango query building and the replication control panel.
Fauxton speaks the same REST API as every other client, so anything you can do in Fauxton you can also do with curl, and vice versa.
Create a Database and a Document
Every CouchDB write is an HTTP request. Create a database with PUT, write a JSON document with POST and list documents with GET:
curl -s -u "admin:$PASSWORD" -X PUT http://localhost:5984/mydb
curl -s -u "admin:$PASSWORD" -X POST http://localhost:5984/mydb \
-H 'Content-Type: application/json' \
-d '{"name":"test","value":42}'
curl -s -u "admin:$PASSWORD" http://localhost:5984/mydb/_all_docs?include_docs=trueThe first call returns {"ok":true}. The second returns {"ok":true,"id":"<generated-uuid>","rev":"1-<hash>"}. The third returns a JSON document that lists every document in the database with its _id, its _rev and, because of include_docs=true, the document body.
Query with Mango
Mango is CouchDB's declarative query language. It uses the same JSON selector syntax as MongoDB and returns results through the /_find endpoint.
Without an explicit index, Mango falls back to a full scan and CouchDB prints a warning. That is fine for ad hoc queries over small databases:
curl -s -u "admin:$PASSWORD" -X POST http://localhost:5984/mydb/_find \
-H 'Content-Type: application/json' \
-d '{"selector":{"name":"test"}}'The response contains a docs array with every document matching the selector. For production use, create an index with POST /<db>/_index so Mango can plan against it.
Create Per Application Users
Never use the admin account for application traffic. Create a per-application user by writing a user document into the built-in _users database. Then grant the user read or write access to a database by PUTting _security on the target database:
curl -s -u "admin:$PASSWORD" -X PUT http://localhost:5984/_users/org.couchdb.user:app1 \
-H 'Content-Type: application/json' \
-d '{"name":"app1","password":"change-me-in-your-secrets-manager","roles":[],"type":"user"}'
curl -s -u "admin:$PASSWORD" -X PUT http://localhost:5984/mydb/_security \
-H 'Content-Type: application/json' \
-d '{"admins":{"names":[],"roles":[]},"members":{"names":["app1"],"roles":[]}}'From the application side, connect with HTTP Basic auth exactly as the admin does, using the new credentials:
curl -s -u "app1:change-me-in-your-secrets-manager" http://localhost:5984/mydb/_all_docs?limit=1CouchDB hashes the stored password on daemon restart, so the plain text in the PUT body above is not persisted.
Rotate the Admin Password
To rotate the admin password, PUT the new value to the admin config endpoint. CouchDB hashes it on the next daemon config read and overwrites /opt/couchdb/etc/local.d/10-admins.ini.
After the rotation, update /stage/scripts/couchdb-credentials.log so future readers see the current value:
NEW_PASSWORD="$(head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 24)" curl -s -u "admin:$PASSWORD" -X PUT \
http://localhost:5984/_node/_local/_config/admins/admin \
-H 'Content-Type: application/json' \
--data "\"$NEW_PASSWORD\""
sudo sed -i "s|^password=.*|password=$NEW_PASSWORD|" /stage/scripts/couchdb-credentials.log export PASSWORD="$NEW_PASSWORD" curl -s -u "admin:$PASSWORD" http://localhost:5984/_upThe final /_up call confirms the new password works. Store the new value in your secrets manager immediately.
Configure Replication
CouchDB replicates when you write a document to the _replicator database that describes the source, target and policy. A pull replication from a remote peer into a local database looks like this:
curl -s -u "admin:$PASSWORD" -X POST http://localhost:5984/_replicator \
-H 'Content-Type: application/json' \
-d '{"_id":"pull-from-peer","source":"http://remote.example.com:5984/mydb","target":"http://admin:local@localhost:5984/mydb","continuous":true}'Replace the source URL with your peer and substitute peer credentials as needed. You can see replication state in Fauxton under Replication, or with GET /_scheduler/docs.
Move Data to an Attached Premium Disk
The default image keeps /opt/couchdb/data on the OS disk. For larger workloads, attach a Premium SSD, format it, mount it at /opt/couchdb/data and restart the service:
sudo systemctl stop couchdb
sudo mkfs.ext4 -F /dev/sdc
sudo mkdir -p /mnt/couchdb-data
sudo mount /dev/sdc /mnt/couchdb-data
sudo rsync -aHAX /opt/couchdb/data/ /mnt/couchdb-data/ echo "/dev/sdc /opt/couchdb/data ext4 defaults,noatime 0 2" | sudo tee -a /etc/fstab
sudo mv /opt/couchdb/data /opt/couchdb/data.old
sudo mkdir /opt/couchdb/data
sudo mount /opt/couchdb/data
sudo chown -R couchdb:couchdb /opt/couchdb/data
sudo systemctl start couchdbVerify the new mount with df -h /opt/couchdb/data and confirm the service came back with systemctl status couchdb.
Troubleshooting
If CouchDB is not reachable, run the following checks in order:
sudo systemctl status --no-pager couchdb
sudo journalctl -u couchdb --no-pager -n 50
sudo tail -n 50 /opt/couchdb/var/log/couchdb.log
sudo ss -tln | grep 5984Common failure modes and their signatures:
couchdb.service: Main process exited, code=exited, status=1/FAILUREwithNo Admin Account Found, aborting startupin couchdb.log: the first-boot service did not write /opt/couchdb/etc/local.d/10-admins.ini before couchdb.service started. Runsudo systemctl start couchdb-firstbootmanually, then restart couchdb.curlreturnsUnauthorized: the password on disk has changed. Export$PASSWORDagain from /stage/scripts/couchdb-credentials.log.curlhangs with no response: port 5984 is not bound. Check the bind_address in /opt/couchdb/etc/local.d/20-sac.ini and confirm the NSG rule.- Replication documents show
errorstate in /_scheduler/docs: the source URL is unreachable or the credentials in the replication document are wrong.
Security Recommendations
CouchDB serves the REST API, the Fauxton admin UI and the replication protocol on port 5984. With a single port, the security posture of that port matters more than for most databases. Before taking customer traffic, apply the following:
- Never expose port 5984 to the public internet. The Fauxton admin UI is on that port. Restrict the NSG rule to your application VNets.
- Rotate the admin password as described in Step 13 and store the new value in your secrets manager. After first boot, do not treat /stage/scripts/couchdb-credentials.log as your source of truth.
- Create a per-application user as described in Step 12, and keep the admin account out of application traffic. Use the admin credential only for admin operations such as creating a database or changing config.
- Terminate TLS with a reverse proxy. nginx in front of CouchDB with a Let's Encrypt certificate gives you HTTPS without changing the CouchDB configuration. Customer applications talk to the proxy, and the proxy talks to localhost:5984.
- Keep CORS disabled unless you serve Fauxton to browsers from another origin. enable_cors = false is the SecureAnyCloud default and is correct for server-to-server traffic.
- Back up /opt/couchdb/data regularly. CouchDB's append-only file format tolerates tarball snapshots of a running database. For point-in-time consistency, stop the service, snapshot the disk and restart.
Support and Licensing
Apache CouchDB is licensed under the Apache License 2.0 and is maintained by the Apache Software Foundation. SecureAnyCloud does not redistribute a modified CouchDB binary. The image uses the upstream package from apache.jfrog.io and adds only the SecureAnyCloud overrides in /opt/couchdb/etc/local.d/20-sac.ini and the first-boot helper under /usr/local/sbin.
For packaging issues, image defects or questions specific to this Azure image, contact SecureAnyCloud support at https://secureanycloud.com. For CouchDB product questions, tuning or bug reports, use the Apache CouchDB community channels at https://couchdb.apache.org.
This guide is maintained at https://secureanycloud.com/guides/couchdb-3-5-on-ubuntu-22-04-azure/.
Deploy on Azure
Launch Apache CouchDB 3.5 on Ubuntu 22.04 on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com