Pl
Applications Azure

Pleasanter on Ubuntu 24.04 on Azure User Guide

| Product: Pleasanter on Ubuntu 24.04 LTS on Azure

Overview

Pleasanter (Implem.Pleasanter) is an open-source no-code / low-code business database platform — a self-hosted alternative to tools like Airtable and kintone. You build your own tables (Pleasanter calls them sites), records, views, dashboards and approval workflow entirely through the browser, with no programming, and drive everything from other systems through a full REST API.

This cloudimg image runs Pleasanter as a ready-to-use appliance: the ASP.NET Core application under Kestrel bound to loopback, a local PostgreSQL database, and nginx in front as the single public entry point. Pleasanter's own login page is the authenticated front door.

Read this before you expose the VM. The application is bound to 127.0.0.1:5000 and cannot be reached from the network directly. nginx on port 80 is the only public listener. Neither the application nor nginx starts until the machine's first boot has built the per-VM database and rotated the Administrator password — so there is no window in which Pleasanter is reachable with a default credential, and the upstream default login (Administrator / pleasanter) is rejected on every deployed VM.

What is included:

  • Pleasanter 1.5.6.1 (the latest upstream release), unmodified, under the AGPL-3.0 licence — a single, fully-featured edition with no licence key and no paywalled tier
  • The ASP.NET Core Runtime 10.0, installed from the Ubuntu 24.04 archive (main) — never from packages.microsoft.com
  • A local PostgreSQL 16 backing store, initialised on first boot with a per-VM schema and per-VM database passwords
  • A per-VM Administrator password and a per-VM API key, generated on first boot and recorded in a root-only file
  • The application bound to 127.0.0.1:5000 only, with a dedicated pleasanter service account (NoNewPrivileges, ProtectSystem, ProtectHome)
  • nginx on port 80 as the only public listener, held closed until first boot completes
  • 24/7 cloudimg support

Pleasanter is a trademark of Implem Inc. cloudimg is an independent packager and is not affiliated with, endorsed by, or sponsored by Implem Inc.

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 a comfortable starting point — the whole stack (the .NET application, PostgreSQL and nginx) uses well under half of that. NSG inbound: allow 22/tcp from your management network and 80/tcp for the application. The image serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Pleasanter, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group my-rg \
  --name pleasanter \
  --image cloudimg:pleasanter:pleasanter:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard
# open the required ports, then read back the public IP
az vm open-port --resource-group my-rg --name pleasanter --port 22 --priority 1001
az vm open-port --resource-group my-rg --name pleasanter --port 80 --priority 1002
az vm list-ip-addresses --resource-group my-rg --name pleasanter \
  --query "[0].virtualMachine.network.publicIpAddresses[0].ipAddress" -o tsv

Step 3 - Retrieve the per-VM credentials

First boot generates a unique Administrator password, a unique API key and unique database passwords, and writes them to a root-only file. SSH in and read them:

sudo cat /root/pleasanter-credentials.txt

The file is 0600 root:root, and both the application and nginx are gated on a bootstrap-ready marker that first boot only creates after the database is built and the Administrator password has been rotated:

Retrieving the per-VM Administrator password, API key and database passwords, the 0600 root:root file permissions, and the bootstrap-ready marker both services wait on

Step 4 - Verify the deployment

Confirm the three services are active and that Kestrel is bound to loopback only while nginx faces the network:

systemctl is-active postgresql pleasanter nginx
ss -ltnp | grep -E ':(80|5000)'
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/

http://127.0.0.1/ returns 302 — Pleasanter redirects an unauthenticated request to its login page. Port 5000 answers only on 127.0.0.1; it is refused on the VM's routable address, so the application is never reachable except through nginx:

The three services active, the listener table showing Kestrel bound to loopback only, and the proof that port 5000 is refused on the routable address while nginx redirects on port 80

Step 5 - Log in to Pleasanter

Open http://<your-vm-ip>/ in a browser. Pleasanter shows its login page. Sign in with the login ID Administrator and the password from /root/pleasanter-credentials.txt:

The Pleasanter login page, the authenticated front door served by nginx on port 80

After signing in you land on the top page, where your tables (sites) appear as tiles alongside the built-in start guide:

The Pleasanter top page after logging in as the per-VM Administrator, showing user-created tables as tiles

Step 6 - Build a table and add records (no code)

This is what Pleasanter is for. From the top page, use the + button to create a new table — choose a Records (Results) table, give it a title such as Team Tasks, and save. You now have a working database table with columns for status, manager, owner and update times, filtering, aggregation and CSV import/export, without writing any code:

A no-code Results table named Team Tasks, populated with records, showing the grid columns, filters and the aggregated record count

Click any row to open the record editor, where you edit the title and body, set a status, owner and manager, attach files, add comments and keep a full change history:

The Pleasanter record editor showing the editable title, body, status, manager and owner fields, the change-history tab and the update controls

Step 7 - Drive it from the REST API

Every table Pleasanter builds is immediately available over a REST API, authenticated with the per-VM API key from /root/pleasanter-credentials.txt. The example below creates a table, adds a record and reads it straight back. It uses the placeholder <API_KEY> — substitute the real key from the credentials file:

API_KEY='<API_KEY>'
BASE=http://localhost
SITE=$(curl -s -H 'Content-Type: application/json' \
  -d "{\"ApiVersion\":1.1,\"ApiKey\":\"$API_KEY\",\"Title\":\"API Demo\",\"ReferenceType\":\"Results\",\"SiteSettings\":{}}" \
  "$BASE/api/items/0/createsite")
SITE_ID=$(echo "$SITE" | sed -n 's/.*"Id":\([0-9]*\).*/\1/p' | head -1)
REC=$(curl -s -H 'Content-Type: application/json' \
  -d "{\"ApiVersion\":1.1,\"ApiKey\":\"$API_KEY\",\"Title\":\"Ship the release\"}" \
  "$BASE/api/items/$SITE_ID/create")
REC_ID=$(echo "$REC" | sed -n 's/.*"Id":\([0-9]*\).*/\1/p' | head -1)
curl -s -H 'Content-Type: application/json' \
  -d "{\"ApiVersion\":1.1,\"ApiKey\":\"$API_KEY\"}" \
  "$BASE/api/items/$REC_ID/get"

Each call returns a 200 status and the read-back returns the record with its title intact — the write path, the schema and API authentication proven in one loop:

The no-code REST API round-trip: create a table, create a record, then read the record back with its title intact

You can create additional API keys per user under each user's API Settings in the Pleasanter UI.

Step 8 - Confirm the security posture

The image ships with no usable credential and no database — everything is minted on first boot:

  • The upstream default login Administrator / pleasanter is rejected; first boot rotates the Administrator password to a per-VM secret before the public listener ever opens.
  • Passwords are stored by Pleasanter as SHA-512 hashes; the credentials file is 0600 root:root.
  • PostgreSQL listens on loopback only, with a per-VM postgres password and dedicated per-VM owner and user roles.
  • Both pleasanter.service and nginx.service carry ConditionPathExists=/var/lib/cloudimg/pleasanter-bootstrap-ready, so if first boot fails, the public listener never opens (fail closed).

Step 9 - Check the runtime and licensing

dotnet --list-runtimes
cat /opt/cloudimg/pleasanter-versions.txt

The ASP.NET Core Runtime 10.0 comes from the Ubuntu archive (noble-updates/main and noble-security/main), so it receives security updates through the normal apt channel, and Pleasanter itself is pinned to release 1.5.6.1:

The installed ASP.NET Core 10 runtime, the Ubuntu archive origin of the package, and the pinned Pleasanter version

Step 10 - Change the Administrator password

Sign in to Pleasanter, open the Administrator account from the user menu, and use Change password. To rotate it from the command line, update the SHA-512 hash directly (Pleasanter hashes passwords as unsalted lowercase-hex SHA-512):

NEWPASS='<new-password>'
HASH=$(printf '%s' "$NEWPASS" | sha512sum | awk '{print $1}')
sudo -u postgres psql -d "Implem.Pleasanter" \
  -c "UPDATE \"Implem.Pleasanter\".\"Users\" SET \"Password\"='$HASH' WHERE \"LoginId\"='Administrator';"

Maintenance

Back up the database. All your tables and records live in the local PostgreSQL database Implem.Pleasanter:

sudo -u postgres pg_dump -Fc "Implem.Pleasanter" > pleasanter-backup.dump

Operating system updates are delivered through Ubuntu's unattended-upgrades, which remains enabled on the image. Reboot when a new kernel is installed. Keep the VM behind your own TLS termination and NSG rules before exposing it to untrusted networks.

Support

Every cloudimg image is backed by 24/7 support. If you have any questions about this deployment, contact the cloudimg team through the Azure Marketplace listing.