Animal Shelter Manager on Ubuntu 24.04 on Azure User Guide
Overview
Animal Shelter Manager (ASM3) is the long-established open-source management system used by animal shelters, rescues and sanctuaries to run their day-to-day operations from one web application. Staff and volunteers record every animal that arrives with its intake reason, species, breed and location on site, then follow it through fostering, reservation, adoption or return to owner. Alongside the animal record sit medical and vaccination schedules, diary entries and tasks, waiting lists, lost-and-found matching, and the people side of the shelter: adopters, fosterers, volunteers, donors and veterinary contacts. Built-in reports and shelter views turn that into the figures a shelter actually has to produce.
The cloudimg image installs ASM3 from the pinned upstream release, runs it as an unprivileged system user behind nginx, and bundles a tuned single-node PostgreSQL database on the same VM so the appliance is completely self-contained. Backed by 24/7 cloudimg support.
What is included:
- Animal Shelter Manager 3, installed from the pinned upstream tag 51-1 (GPL-3.0), laid out where upstream's own Debian package puts it (
/usr/lib/sheltermanager3, config/etc/asm3.conf) - A bundled PostgreSQL 16 database on the same VM, tuned for the VM size rather than left at stock defaults, listening on loopback only
- The application bound to
127.0.0.1:5000and fronted by nginx on port 80, with an unauthenticated/healthzfor load-balancer probes - No usable default login. Upstream ASM3 seeds a documented
user/letmeinsuperuser and aguest/guestaccount. This image removesguestentirely and ships every account locked; a unique administrator password, database password and PostgreSQL superuser password are generated on the first boot of each VM asm3-credential-audit.pyandasm3-admin-password.pyshipped as tools so you can prove no publicly known credential works, and rotate the admin password from the shell- Report and document generation via WeasyPrint, ReportLab and xhtml2pdf; XLSX export via openpyxl
- Fully patched base with unattended security upgrades enabled
- 24/7 cloudimg support

Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is the recommended size and comfortably runs both the application and the bundled database for a typical shelter; choose a larger size if you have many concurrent staff users or a large media library. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web interface. Nothing else needs to be open - the database and the application process are bound to loopback and are not reachable from the network.
The appliance serves plain HTTP on port 80 on the VM's own IP so you can evaluate it immediately. Add a real hostname and a TLS certificate before you store live animal, adopter or veterinary records - see "Set your own domain and TLS".
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Animal Shelter Manager by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size (Standard_B2s); under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create followed by Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name animal-shelter-manager \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Then open the web port on the VM's NSG:
az vm open-port --resource-group <your-rg> --name animal-shelter-manager --port 80 --priority 900
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm the services are running
On first boot the image generates this VM's administrator password, its PostgreSQL role password and a password for the PostgreSQL superuser, points the application at the VM's own address, and starts the stack. Confirm all four services are active:
systemctl is-active postgresql memcached nginx asm3
Only port 80 is reachable from outside the VM. The application itself, the database and the cache are all bound to the loopback interface:
sudo ss -tlnp | grep -E ':80 |:5000 |:5432 |:11211 '

Step 5 - Check the health endpoint
The unauthenticated /healthz endpoint returns 200 and is intended for load-balancer and monitoring probes. It deliberately exposes nothing about the shelter:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz
The ASM3 login page itself should also return 200:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/login
Step 6 - Retrieve the per-VM administrator credentials
Every secret on this VM is generated on its first boot and written to a root-only file. Nothing is shared with any other deployment of this image:
sudo cat /root/asm3-credentials.txt
The file records the web URL, the administrator username and password, the ASM3 database name, username and password, and the PostgreSQL superuser password.

Step 7 - Confirm the upstream default login does not work
This is the single most important difference between this image and a hand-rolled ASM3 install. Upstream ASM3 seeds two accounts into every new database and publishes both in its own manual: user with the password letmein, which is a superuser, and guest with the password guest.
On this image the guest account is deleted outright, and the user account ships with a password hash that cannot be satisfied by any input until first boot replaces it with a random per-VM password. Prove it for yourself - both of these return FAIL:
curl -s -X POST http://127.0.0.1/login --data-urlencode 'username=user' --data-urlencode 'password=letmein' --data-urlencode 'database='; echo
curl -s -X POST http://127.0.0.1/login --data-urlencode 'username=guest' --data-urlencode 'password=guest' --data-urlencode 'database='; echo
A shipped audit tool checks every account row against upstream's published defaults and the usual weak passwords, using ASM3's own password-verification code. Run it at any time:
sudo /usr/local/sbin/asm3-credential-audit.py
It prints CREDENTIAL_AUDIT_CLEAN and exits 0 when no publicly known credential works.

Step 8 - Sign in to the web interface
Browse to http://<vm-public-ip>/ and sign in with the username and password from the credentials file. You land on the ASM3 main screen: quick links to the shelter and calendar views, a recently-changed strip, the shelter overview counters, alerts, your diary and a timeline of shelter activity.

Important - ASM3 redirects to its configured address. ASM3 records its own base URL in
/etc/asm3.confand, if the address in your browser does not match it, redirects you there. First boot sets it to this VM's public IP, so browsing to the VM's IP works out of the box. If you put a DNS name, a load balancer or a reverse proxy in front of the VM, you must updatebase_urlandservice_urlin/etc/asm3.confand restartasm3.service, or the browser will be redirected back to the raw IP. This also means an SSH port-forward tolocalhostwill not work until you changebase_urlto match.
Step 9 - Add your first animal
Choose ASM then Add an animal, give the animal a name, species, sex and an estimated age or date of birth, pick an entry reason and a location on the shelter, and select Save. ASM3 generates a shelter code automatically and opens the full animal record, with tabs for vaccinations, tests, medical treatment, clinic appointments, licences, diet, costs, payments, media, diary, transport and movements.

The shelter view groups every animal currently on the shelter by location, so you can see the whole shelter at a glance and drag animals between locations:

Step 10 - The bundled PostgreSQL database
The database runs on this same VM and is bound to the loopback interface, so it is never exposed to the network. It is tuned for the VM size rather than left at PostgreSQL's stock defaults - the settings below are what the image ships:
sudo -u postgres psql -tAc "SELECT name || ' = ' || setting || COALESCE(unit,'') FROM pg_settings WHERE name IN ('listen_addresses','shared_buffers','effective_cache_size','work_mem','max_connections','random_page_cost') ORDER BY name"
Animal records live in the animal table of the asm database. You can read them directly, which is useful for reporting or for confirming a backup:
sudo -u postgres psql -d asm -c "SELECT ID, AnimalName, ShelterCode, DateBroughtIn::date AS entered FROM animal ORDER BY ID"

Step 11 - Back up the shelter database
The shelter database is the thing you cannot recreate. Take a compressed dump with the PostgreSQL superuser password from the credentials file, and copy it off the VM:
sudo -u postgres pg_dump -Fc asm > /var/tmp/asm-backup-$(date +%Y%m%d).dump && ls -lh /var/tmp/asm-backup-*.dump
Media such as animal photos and scanned paperwork is stored on the filesystem under /var/lib/sheltermanager3/media, which keeps the database small; back that directory up alongside the dump. Restore with pg_restore into an empty database.
Step 12 - Change the administrator password
Change the password from Settings then System user accounts in the web interface, or from the shell with the shipped tool. It hashes the password exactly as the web interface does and refuses to report success unless the new password then genuinely authenticates:
sudo /usr/local/sbin/asm3-admin-password.py user '<your new password>'
Create individual named accounts for your staff rather than sharing the administrator login, and give each one only the roles it needs.
Set your own domain and TLS
The appliance boots on plain HTTP on the VM's IP so you can evaluate it immediately. Before you enter real animal, adopter or veterinary records:
- Point a DNS record (for example
shelter.example.org) at the VM's public IP. - Install a certificate, for example with
sudo apt-get install certbot python3-certbot-nginxandsudo certbot --nginx -d shelter.example.org. Certbot updatesserver_namein/etc/nginx/sites-available/asm3and adds the TLS listener. - Update
/etc/asm3.confso ASM3 knows its own address - setbase_url = https://shelter.example.organdservice_url = https://shelter.example.org/service, and setsession_secure_cookie = truenow that the site is HTTPS-only. - Restart the application so the new configuration is loaded:
sudo systemctl restart asm3 nginx
Step 3 is not optional. ASM3 redirects any request whose address does not match base_url, so a certificate without the matching configuration change will bounce your browser back to the IP.
Maintenance and production notes
- Logs: the application logs to
/var/log/asm3/asm3.log, rotated weekly. Usejournalctl -u asm3for service-level start-up problems andjournalctl -u asm3-firstbootto see what first boot did. - Scheduled tasks: ASM3's daily batch (animal figures, diary and waiting-list maintenance, publishing) runs from
cron.py. Review/usr/lib/sheltermanager3/cron.py allif you want to schedule it, and set your organisation's details in Settings then Options first. - Email: no mail transport is configured in the image. Set
smtp_serverandfrom_addressin/etc/asm3.confbefore using the email, mail-merge or online-form features. - Updates: apply OS security updates with
sudo apt update && sudo apt upgrade; unattended security upgrades are already enabled. ASM3 version upgrades follow upstream's release notes and requirepython3 cron.py maint_db_updatefrom/usr/lib/sheltermanager3after replacing the application tree. - Security: this image ships no usable default credential. Keep
/root/asm3-credentials.txtprotected, delete it once you have stored the passwords elsewhere, and re-runsudo asm3-credential-audit.pyafter any user administration to confirm nothing weak crept in.
Animal Shelter Manager is free software licensed under the GPL-3.0. This image is produced by cloudimg and is not affiliated with, sponsored by, or endorsed by the Animal Shelter Manager project or Sheltermanager Ltd.