Skip to content

Deploy an application and its database

A runtime, dependencies, a database that keeps its tables. The reflex is to reach for one managed service per need. In a lab, you take one VM and put the database on it. I’ll tell you why, then we’ll set it up.

The question The answer that puts you here
What are you running? A process of your own: an API, a back end, a job, a binary, a container.
Do you need to install things? Yes: a runtime, system packages, tools of your choosing.
Must your data survive a restart? Yes, hence the database.
Is the lab about a specific Azure service? No. If your subject is a managed service, this tutorial doesn’t apply.

If you’re only serving already-built files, take the shorter scenario: deploy a static site.

It all comes down to one line of the table: auto-shutdown only covers VMs.

Database installed on the VM Managed database service
Billing Follows the VM, so follows auto-shutdown. Around the clock for as long as the resource exists.
Auto-shutdown Yes, the database stops with the machine at 7 pm. Not covered. Nothing turns it off for you.
Setup A few minutes, one package manager. A resource to create, plus networking and access rules to configure.
What you learn You run the database yourself. Backups and availability handled for you, out of sight.
In a lab The default case. Only if the lab’s subject is that service.

The classic trap: the managed database created “for two days of testing” and forgotten until the lab’s expiry date. It billed ninety nights and two months of weekends while the VM slept. See Costs.

A Resource Group created with its tags and a declared lab. If not: create my Azure lab. The VM is created in that Resource Group.

  1. In the Azure portal, create a Virtual machine resource in your Resource Group and in the lab’s region.

  2. Choose an Ubuntu Server LTS image and a modest size, for example Standard_B2s (2 vCPUs, 4 GiB). Available sizes vary from region to region. For the disk, Standard SSD is enough.

  3. Keep SSH key authentication and download the private key. No password: that’s the door automated scans find first.

  4. At the networking step, set Public inbound ports to None. The default opens the SSH port to the whole world, which is never acceptable, not even for an hour.

  5. In the Tags tab, fill in owner, projectName and creationDate, the three without which creation is refused, then expirationDate. The portal applies these tags to all the resources the wizard creates: the network interface, public IP, NSG and disk need them just as much as the VM.

  6. Take a Standard public IP, which is static. A dynamic IP changes every time the machine is deallocated, and the 7 pm auto-shutdown triggers that every evening.

  7. Once the VM is created, open its NSG — Azure’s firewall, see the glossary — and add an inbound rule allowing port 22 from the single allowed IP, 194.148.102.82 (the egress of Chancy). This isn’t your computer’s address: your connection must go out through Chancy. Then connect over SSH with the downloaded key.

The example installs PostgreSQL and prepares a database for the application. Swap in another engine if you like; the approach doesn’t change.

Terminal window
sudo apt update
sudo apt install -y postgresql
# The database only listens on the machine itself: the default configuration on
# Ubuntu, and exactly what you want here.
sudo -u postgres psql -c "SELECT inet_server_addr();"
# A dedicated user and database for the application.
sudo -u postgres psql -c "CREATE USER app WITH PASSWORD 'a-generated-password';"
sudo -u postgres createdb --owner=app appdb
# Check from the machine.
psql "postgresql://app:a-generated-password@localhost/appdb" -c "\l"

The application runs on the same machine and connects to localhost. No database port is open on the network, so there’s no NSG rule to write for the database.

To reach the application from your computer: an SSH tunnel, ssh -L 8080:localhost:8080 azureuser@your-ip, and nothing is exposed — it’s the shortest path, since port 22 is already open. Otherwise, an NSG rule on the application’s port, with 194.148.102.82 as the source just like SSH, never 0.0.0.0/0.

What catches you out after the first night

Section titled “What catches you out after the first night”
The symptom What’s going on
The application no longer responds in the morning The VM was stopped at 7 pm. That’s an enforced rule, not an incident. Restart it, and make sure your services start on their own (systemctl enable).
The database “lost” its connections It stopped with the machine. The data is there, the open connections aren’t. It’s up to your application to reconnect.
The address changed The public IP was dynamic. Switch it to static.
SSH doesn’t respond, or times out The rule only allows 194.148.102.82: your connection isn’t going out through Chancy. Check your address as seen from outside (curl ifconfig.me) before suspecting the VM. Don’t widen the rule to compensate.
A deployment refused because of a policy An ancillary resource was created without the mandatory tags: network interface, disk, public IP or NSG.
The disk fills up Logs, container images and dumps pile up fast. Free up space rather than growing the disk.

The VM’s disk is not backed up. Run a regular pg_dump to your computer or a Git repository, and keep the schema versioned rather than rebuilt by hand. At the lab’s expiry date, the Resource Group disappears, and the database with it.

The Resource Group is deleted at the expiry date by the lab administrators, taking the VM, its disk and the database with it. If you no longer need it before then, delete it right away: see lifecycle, extension and closure. In the meantime, the Cost analysis screen filtered on your Resource Group gives the lab’s actual cost.

A lab whose subject is AKS, a managed database or a gateway calls for a cost and sizing trade-off before anything is created. Read Costs, then write to lab@qiminfo.ch saying what you want to test and for how long.