Deployment guide

Atuin

Overview

Atuin is a self-hosted sync server for shell history. The Atuin terminal client records your shell history into an encrypted, searchable database, and this server synchronizes it across all of your machines. History is encrypted end to end with a key that never leaves your own machines, so the server stores only opaque encrypted records and your command history stays private on infrastructure you control.

This SecureAnyCloud image runs the official prebuilt Atuin server Rust binary on Ubuntu 24.04 on Azure. The binary is pinned to a release version, checksum verified, and run under systemd as a dedicated service bound to the loopback interface. A local PostgreSQL 16 instance is the backing store, and nginx reverse proxies the sync API on port 80, ready for your TLS certificate.

What you get:

  • The official Atuin server binary (atuin-server), checksum verified and run under systemd, bound to the loopback interface.
  • A local PostgreSQL 16 backing store, listening on the loopback interface only.
  • An nginx reverse proxy on port 80, ready for your TLS certificate.
  • Open registration disabled. Atuin's server normally lets anyone register an account, which turns a public deployment into an open sign-up service. This image sets open_registration = false in /etc/atuin/server.toml, so the appliance is single-tenant. Step 9 shows how to enable registration to invite more people.
  • No baked credentials. On first boot, the PostgreSQL atuin role password and a per-VM Atuin account are generated with independent random values. A root-only summary is written to /root/atuin-credentials.txt. The application database is dropped when the image is built, so every deployed VM starts from a clean database with fresh credentials.
  • A demo history record seeded on first boot, so the sync API is provably live.
  • Client-side end-to-end encryption. The Atuin client generates the key on your own machine, and it is never stored on the server.
  • Unattended security upgrades left enabled so the appliance keeps receiving patches.

Prerequisites

  • An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region.
  • A subscription to the Atuin listing on Azure Marketplace.
  • A Network Security Group (NSG) rule that allows TCP 22 (administration) and TCP 80 (the sync API) from the networks that need them.

Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) for personal or small-team sync. For a larger team or a bigger history store, use Standard_D2s_v5 or larger and attach a data disk for the PostgreSQL data directory.

1

Deploy from the Azure Portal

Search the Azure Marketplace for Atuin, select the SecureAnyCloud publisher, and click Create.

Configure the Network Security Group to allow TCP 22 for administration and TCP 80 for the sync API from the networks that need them. No inbound database port is required, because the bundled PostgreSQL listens on loopback only.

2

Deploy from the Azure CLI

Accept the Marketplace terms once per subscription, then create the VM and open ports 22 and 80:

RG="atuin-prod"; LOCATION="eastus"; VM_NAME="atuin1" IMAGE_URN="sac1647283583153:atuin-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:atuin-ubuntu-24-04:default:latest
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$IMAGE_URN" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard
# Open the admin and sync ports on the VM's NSG:
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1002
3

First boot

On first boot, the image starts PostgreSQL on the loopback interface and generates a per-VM password for the atuin database role. It recreates a clean application database, seeds a per-VM Atuin account and a demo history record, and writes /root/atuin-credentials.txt. This completes within a minute.

SSH in as azureuser and read the details:

sudo cat /root/atuin-credentials.txt

The file contains the sync address, the seeded account username, its password and the PostgreSQL password. Store it somewhere safe.

4

Confirm the service is healthy

Confirm that the Atuin server, nginx and PostgreSQL are all active. The Atuin server binds only to the loopback interface, and nginx serves the unauthenticated /healthz endpoint on port 80.

systemctl is-active atuin.service nginx.service postgresql.service echo '--- atuin and PostgreSQL are loopback only (no public app/db port) ---' ss -tlnH | grep -E ':8888 |:5432 ' | awk '{print $4}' | sort -u echo -n '/healthz through nginx :80 -> HTTP ' curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz
5

Confirm open registration is disabled

The appliance is single-tenant. Because open_registration is false, a new registration attempt against the sync API is refused with HTTP 400. This keeps a public deployment from becoming an open sign-up service.

echo '--- server.toml: loopback bind + open registration disabled ---' sudo grep -E '^(host|port|open_registration)' /etc/atuin/server.toml
echo -n 'POST /register (should be refused) -> HTTP ' curl -s -o /dev/null -w '%{http_code}\n' -H 'Content-Type: application/json' \
  -d '{"username":"someone","email":"someone@example.com","password":"changeme12345"}' \
  http://127.0.0.1/register
6

Test the sync API with an account round-trip

The per-VM account seeded on first boot authenticates through the real sync API. The commands below log in for a session token and confirm the account at the authenticated /api/v0/me endpoint. They then store a history record and read the record count back, which is the same round-trip the Atuin client performs when it syncs.

U=$(sudo grep '^ATUIN_ACCOUNT_USERNAME=' /root/atuin-credentials.txt | cut -d= -f2-)
P=$(sudo grep '^ATUIN_ACCOUNT_PASSWORD=' /root/atuin-credentials.txt | cut -d= -f2-)
TOKEN=$(curl -s -H 'Content-Type: application/json' -d "{\"username\":\"$U\",\"password\":\"$P\"}" http://127.0.0.1/login | jq -r .session)
echo "Logged in as $U; session token: ${TOKEN:0:12}..."
echo -n 'GET /api/v0/me -> '; curl -s -H "Authorization: Token $TOKEN" http://127.0.0.1/api/v0/me echo;
echo -n 'History records before: '; curl -s -H "Authorization: Token $TOKEN" http://127.0.0.1/sync/count | jq -r .count curl -s -o /dev/null -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d "[{\"id\":\"guide-$(date +%s%N)\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"data\":\"encrypted-history-blob\",\"hostname\":\"my-laptop\"}]" \
  http://127.0.0.1/history
echo -n 'History records after: '; curl -s -H "Authorization: Token $TOKEN" http://127.0.0.1/sync/count | jq -r .count
7

The PostgreSQL backing store

Atuin stores its accounts, sessions, and encrypted history and record data in the bundled PostgreSQL 16 database. The server creates the schema automatically the first time it starts. List the tables:

sudo -u postgres psql -d atuin -c '\dt'
8

Connect the Atuin client

On each of your own machines, install the Atuin client, point it at this server, and log in with the seeded account (or your own, once you enable registration). Generate your encryption key on your first machine and copy it to the others. The key never touches the server.

Run these commands on your own machine, not on the VM:

# On your own machine (see https://docs.atuin.sh): atuin login --username sac --password '<password from /root/atuin-credentials.txt>' \
  --sync-address http://<your-vm-address>/ atuin key
# print your encryption key (run on the first machine) atuin sync
# sync your shell history through your server

To set the sync address permanently, add it to your client config (~/.config/atuin/config.toml):

sync_address = "http://<your-vm-address>/"
9

Invite more people (enable registration)

To let other people register their own accounts, set open_registration = true in /etc/atuin/server.toml on the VM and restart the service. Turn it off again once everyone has registered.

sudo sed -i 's/^open_registration = false/open_registration = true/' /etc/atuin/server.toml
sudo systemctl restart atuin.service
# ... let people run: atuin register -u <name> -e <email> -p <password> --sync-address http://<your-vm-address>/
# then disable it again:
sudo sed -i 's/^open_registration = true/open_registration = false/' /etc/atuin/server.toml
sudo systemctl restart atuin.service
10

Add TLS

The nginx reverse proxy is ready for a certificate. Point a DNS name at the VM and open TCP 443 on the NSG. Install a certificate with your preferred tool, for example certbot with the nginx plugin.

Then set the sync address on your clients to the https:// URL.

11

Security recommendations

Keep the database private. The bundled PostgreSQL listens on loopback only, and no database port is exposed. Never expose port 5432 or 8888 publicly. Reach the server only through nginx.

Restrict the NSG. Allow TCP 22 from your management network, and allow TCP 80 or 443 only from the networks that sync.

Leave open registration off. Enable it only while you invite users, then disable it again (Step 9). Anyone who can register can store encrypted blobs on your server.

Use TLS in production. Serve the sync API over HTTPS (Step 10) so client tokens are never sent in clear text.

Back up PostgreSQL. Your accounts and encrypted history live in the atuin database. Back it up like any production database, and consider an encrypted data disk for the data directory.

Keep the OS and Atuin patched. Unattended security upgrades remain enabled on the running VM. Upgrade the Atuin server binary when new releases ship.

12

Support and Licensing

Atuin is developed by the Atuin project and distributed under the MIT license. This SecureAnyCloud image bundles the unmodified official Atuin server binary.

SecureAnyCloud provides the packaging, the secure-by-default configuration (loopback only, open registration disabled), the PostgreSQL backing store and nginx reverse proxy, first-boot credential generation, and 24/7 support with a guaranteed 24 hour response SLA.

SecureAnyCloud is not affiliated with or endorsed by the Atuin project. Atuin is a mark of its respective owner and is used here only to identify the software.

Deploy on Azure

Find Atuin on Ubuntu 24.04 LTS on the Azure Marketplace, published by SecureAnyCloud. Deploy from the Portal or the Azure CLI as shown above.

Need Help?

Email sales@secureanycloud.com for deployment help, configuration questions, or licensing enquiries.

Deploy on Azure

Launch Atuin 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