Deployment guide

LibreSign

Overview

LibreSign is an open-source digital document-signing platform from LibreCode coop. It gives an organisation a controlled signing workflow. You upload a document, choose who signs it and in what order, track the request, and produce a signed PDF that carries a real cryptographic signature that anyone can validate.

LibreSign is built and distributed as an application for Nextcloud, so this SecureAnyCloud image delivers the whole stack: the Nextcloud 34.0.3 server that stores the documents and holds the accounts, the LibreSign 14.1.0 application, and the complete signing toolchain it needs.

The toolchain is the part that usually goes wrong. On a hand-built instance, LibreSign must download a Java runtime, JSignPdf and pdftk from the internet on first use, and an administrator has to click through that flow before anything can be signed. This image does none of that. Every binary is fetched, checksum-verified and installed at build time, so the appliance signs documents the moment it boots, even on a network with no outbound access.

What you get:

  • LibreSign 14.1.0 (AGPL-3.0-or-later) running on Nextcloud 34.0.3 (AGPL-3.0-or-later)
  • The complete signing toolchain, pre-provisioned offline: Eclipse Temurin JRE 21.0.8+9, JSignPdf 2.3.0, pdftk-java 3.3.3, poppler-utils and the PHP Imagick extension
  • nginx terminating TLS on :443 with a per-VM certificate, and :80 redirecting to it
  • PHP 8.3-FPM over a unix socket, a local PostgreSQL 16 database and a password-protected Redis, all reachable only on loopback
  • A dedicated 60 GiB Azure data disk at /var/lib/libresign, holding both your documents and the database
  • A LibreSign root certificate authority generated uniquely on the first boot of every VM, never baked into the image
  • A per-VM administrator password, database password and Redis password, generated on first boot and recorded in a root-only file
  • nginx.service, php8.3-fpm.service, postgresql.service and redis-server.service as enabled systemd units, plus a five-minute background-jobs timer
  • 24/7 SecureAnyCloud support

SecureAnyCloud is not affiliated with, endorsed by or sponsored by LibreCode coop or Nextcloud GmbH. LibreSign and Nextcloud are the trademarks of their respective owners and are used here only to identify the software this image packages.

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B4ms (4 vCPU / 16 GiB RAM) is a good starting point. Signing runs a JVM, so do not go below 4 GiB of RAM.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 443/tcp from wherever your signers are. Port 80/tcp is only needed for the automatic redirect to HTTPS, for people who type a bare address.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for LibreSign by SecureAnyCloud, and select Create.

On the Basics tab, 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 HTTPS (443).

Review the dedicated 60 GiB data disk on the Disks tab, then select Review + create and Create.

Step 2 - Deploy from the Azure CLI

Create the VM and open port 443:

az vm create \
  --resource-group <your-rg> \
  --name libresign \
  --image <marketplace-image-urn> \
  --size Standard_B4ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name libresign --port 443 --priority 1010

Step 3 - Connect to your VM

Connect over SSH as azureuser:

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

The web tier, PHP runtime, database and cache all run as systemd units. Check that they are active:

systemctl is-active nginx.service php8.3-fpm.service postgresql.service redis-server.service

Expect this output:

active active active active

The background-jobs timer runs Nextcloud's cron.php every five minutes. Confirm that the timer is enabled:

systemctl is-enabled libresign-cron.timer
enabled

Step 5 - Retrieve your per-VM credentials

Nothing in this image ships with a known password. On the first boot of every VM, libresign-firstboot.service generates a fresh administrator password, database password, Redis password, TLS certificate and LibreSign root certificate authority. It then writes the credentials to a root-only file. Read the file:

sudo cat /root/libresign-credentials.txt

The file lists the URL to open, the admin account and its password, the database and Redis passwords, this VM's Nextcloud instance ID, and the SHA-256 fingerprint of the root certificate authority that this VM created for itself. No two VMs launched from this image share any of these values.

Confirm that only root can read the file:

sudo stat -c '%a %U:%G' /root/libresign-credentials.txt
600 root:root

Step 6 - Sign in to LibreSign

Open https://<vm-public-ip>/ in a browser. The certificate is self-signed for this VM's address, so your browser warns once. Accept it, or replace the certificate with your own as described in Step 11.

Sign in as admin with the password from Step 5. The image sets LibreSign as the default application, so you land on the Request Signatures screen rather than a generic dashboard.

Step 7 - Request a signature

Under Request, choose Upload and pick a PDF. After the upload, select Add signer, search for the account or e-mail address that should sign, and select Save. Repeat for each signer.

When the signer list is complete, choose Request signatures and confirm with Send. The document moves from Draft to Ready to sign, and each signer is listed with their own status.

Step 8 - Sign the document

Choose Sign document. The first time an account signs, LibreSign asks it to create a signing password. That password protects a signing certificate that LibreSign issues to the account from this VM's own root certificate authority. Enter the password and confirm.

LibreSign then applies the signature with the bundled JSignPdf and stamps the signature footer with pdftk. When it finishes, the document reports Signed, and LibreSign confirms that the signature is valid.

Anyone can check a signed file later. Open Validate in the left-hand menu, then upload the PDF or enter the document's identifier.

Step 9 - Verify the signing toolchain

LibreSign signs nothing unless its external binaries are present at exactly the pinned versions and match the SHA-512 manifests that LibreCode signs and ships inside the application. This image satisfies all of that at build time. Check it from the shell at any point:

sudo /usr/local/sbin/libresign-check.sh

Every row reports success: the Temurin JRE, JSignPdf, pdftk, poppler and Imagick, plus the root certificate authority.

The same table appears in the web interface under Settings > Administration > LibreSign, together with the details of the root certificate this VM generated for itself.

Use the wrapper script above rather than calling occ libresign:configure:check directly. That command prints its status table but always exits 0, so its exit code cannot serve as a health check. The wrapper parses the table and fails if any row reports an error.

Step 10 - Check the exposed surface

Only three TCP ports are reachable from outside the VM. List them:

ss -H -ltn | awk '{print $4}' | grep -vE '^(127\.|\[::1\])' | sed -E 's/.*:([0-9]+)$/\1/' | sort -un | tr '\n' ' '
22 80 443

PostgreSQL and Redis are bound to loopback only, and Redis also refuses unauthenticated connections:

redis-cli ping
NOAUTH Authentication required.

Plain HTTP exists only to redirect to HTTPS:

curl -s -o /dev/null -w 'HTTP %{http_code} -> %{redirect_url}\n' http://127.0.0.1/
HTTP 301 -> https://127.0.0.1/

An unauthenticated health endpoint is served on both ports, which suits a load balancer probe:

curl -ks https://127.0.0.1/health
ok

Step 11 - Use your own domain and certificate

The image trusts the addresses it detected on first boot. To reach the instance on your own DNS name, add the name to the trusted domain list and set the canonical URL:

sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 4 --value sign.example.com
sudo -u www-data php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value https://sign.example.com/

Never set a * wildcard there. It disables the host-header validation that protects password-reset links.

Then replace the self-signed certificate with your own, keeping the same paths, and reload nginx:

sudo install -m 0644 fullchain.pem /etc/nginx/ssl/libresign.crt
sudo install -m 0600 privkey.pem /etc/nginx/ssl/libresign.key
sudo systemctl reload nginx

Step 12 - Where your data lives

Both the documents and the database sit on the dedicated data disk. The disk is captured into the image and re-provisioned on every VM. Check the mount:

df -h /var/lib/libresign | tail -1
/dev/sda 59G 328M 56G 1% /var/lib/libresign

/var/lib/libresign/data is the Nextcloud data directory. It holds your documents and, under appdata_<instance-id>, the pre-provisioned signing toolchain and this VM's root certificate authority. /var/lib/libresign/pgsql/main is the PostgreSQL data directory.

Back up that one mount point and you have backed up the appliance's state. Confirm that the platform is the pinned version:

sudo -u www-data php /var/www/nextcloud/occ status
- installed: true - version: 34.0.3.2 - versionstring: 34.0.3 - edition: - maintenance: false - needsDbUpgrade: false - productname: Nextcloud - extendedSupport: false

Step 13 - Add the people who will sign

Signers are ordinary accounts. In the browser, create them under Settings > Administration > Accounts. Or create one from the shell:

sudo -u www-data OC_PASS='<a-strong-password>' php /var/www/nextcloud/occ user:add --password-from-env --display-name "Jane Doe" jane

LibreSign can also send a request to an e-mail address that has no account yet. First configure an SMTP server under Settings > Administration > Basic settings. Without it, those invitations are not delivered.

Troubleshooting

The browser says the connection is not private. This is expected on a fresh VM, because the certificate is self-signed for the VM's IP address. Accept it once, or install your own certificate as in Step 11.

"Access through untrusted domain". You reached the VM on a name or address that is not in trusted_domains. Add it as in Step 11.

A signature fails with a Java or JSignPdf error. Run sudo /usr/local/sbin/libresign-check.sh first. It names the failing component. The most common cause on a modified instance is an upgraded binary, because LibreSign requires exactly the pinned versions and rejects newer ones.

First boot did not complete. Check the one-shot unit that generates every secret:

systemctl status libresign-firstboot.service --no-pager | head -20

Where are the logs? nginx logs to /var/log/nginx/, and Nextcloud logs to /var/lib/libresign/data/nextcloud.log.

Support

Every SecureAnyCloud image is backed by 24/7 support. Contact sales@secureanycloud.com with your Azure subscription and VM name.

Deploy on Azure

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