Security Azure

Password Pusher on Ubuntu 24.04 on Azure User Guide

| Product: Password Pusher on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Password Pusher on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Password Pusher is an open source, self hosted web application for sharing sensitive information securely and temporarily. A sender pushes a password, block of text, a file or a URL and receives a one time link; the link stops working automatically once it has been viewed a set number of times or a set number of days have passed, whichever comes first, and every push is tracked with an audit trail. It is a simpler, private alternative to emailing credentials or using a public paste service.

The image builds the Password Pusher application reproducibly from source at build time (the exact version and source commit are recorded in /opt/passwordpusher/VERSION). The application is a Ruby on Rails app that runs under systemd on the puma web server as the unprivileged passwordpusher system user, bound to loopback only (127.0.0.1:5100). nginx is the sole network facing surface and terminates TLS on port 443, reverse proxying to Password Pusher. Data is held in a local SQLite database, and push payloads are encrypted at rest.

This appliance is anonymous by design. It ships with the login and signup system disabled, so there is no admin account and no credential of any kind is ever baked into the image. Pushing a secret needs no login. The only per instance secrets are generated on first boot for this specific VM and are never shared between instances: the Rails session signing key (SECRET_KEY_BASE), the database payload encryption key (PWPUSH_MASTER_KEY), and the self signed TLS private key (whose Subject Alternative Names include the VM public IP, hostname and 127.0.0.1).

What is included:

  • Password Pusher built from source and run under systemd on puma as the unprivileged passwordpusher system user

  • The application bound to loopback only (127.0.0.1:5100) — it is never network exposed directly

  • nginx terminating TLS on :443 and reverse proxying to Password Pusher, with HSTS and sensible security headers

  • Port :80 returns a 301 redirect to HTTPS for every path except an unauthenticated /healthz endpoint (HTTP 200) for load balancer probes

  • A self signed TLS certificate regenerated per VM on first boot (SAN includes the VM public IP + hostname) — replace it with your own CA signed certificate for production

  • A local SQLite database with push payloads encrypted at rest using a per VM key generated on first boot

  • A built in one time self test at /opt/passwordpusher/passwordpusher-selftest.sh that proves the self destruct semantics end to end over TLS

  • Ubuntu 24.04 LTS base with latest security patches applied at build time

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • An Azure subscription with permission to deploy virtual machines

  • An SSH key pair for administrative access to the VM as the azureuser account

  • A Network Security Group allowing inbound TCP 443 (HTTPS) and 80 (redirect) from the networks that should reach the service, and 22 (SSH) from your management network only

  • A recommended size of Standard_B2s or larger

Step 1: Deploy from the Azure Portal

  1. Locate the Password Pusher on Ubuntu 24.04 LTS by cloudimg image in the Azure Marketplace and select Create.

  2. Choose your subscription, resource group and region.

  3. Select a VM size (Standard_B2s or larger) and provide your SSH public key for the azureuser account.

  4. On the Networking tab, allow inbound 443 and 80 from your users, and restrict 22 to your management network.

  5. Review and create. When the VM is running, browse to https://<your-public-ip>/.

Step 2: Deploy from the Azure CLI

You can deploy the same image from the Azure CLI. Replace the resource group, location and image URN as needed:

az vm create \
  --resource-group my-passwordpusher-rg \
  --name passwordpusher \
  --image <cloudimg-passwordpusher-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard
# then open the required ports
az vm open-port --resource-group my-passwordpusher-rg --name passwordpusher --port 443 --priority 1001
az vm open-port --resource-group my-passwordpusher-rg --name passwordpusher --port 80 --priority 1002

Step 3: Verify the Password Pusher and nginx services

SSH in as azureuser and confirm the services are active and that Password Pusher is bound to loopback only, with nginx the only public listener:

sudo systemctl is-active passwordpusher nginx
sudo ss -tln | grep -E ':5100 |:80 |:443 '

You should see puma on 127.0.0.1:5100 (loopback only), while nginx listens on 0.0.0.0:80 and 0.0.0.0:443.

systemctl reports passwordpusher and nginx both active; ss shows puma bound to 127.0.0.1:5100 loopback only, with nginx public on :80 and :443

Step 4: Open the Password Pusher web interface

Browse to https://<your-public-ip>/. Because the certificate is self signed and generated per VM, your browser will warn about the certificate the first time. Accept it (or install your own certificate, see Step 12). You are presented with the Push a Password form: type or paste your secret, and choose how long it should live using Expire After Days and Expire After Views.

The Password Pusher push form with a secret entered and the Expire After Days and Expire After Views controls, ready to generate a one time link

Step 5: Push a secret and get a one time link

Select Push it!. Password Pusher stores the secret encrypted and shows a secret link you can share with the recipient. The page explains that the link will expire after the configured number of views or days, so you should send it to the recipient rather than opening it yourself.

The generated secret link page showing the one time URL to share and the expiration settings for the push

Step 6: Reveal the secret

When the recipient opens the link, Password Pusher displays the secret, with a note showing how many views remain before it expires. This counts as one view.

The retrieved secret view showing the revealed password and the remaining views before the link expires

Step 7: Confirm the secret expires

Once the view limit is reached, opening the same link again proves the expiry guarantee: the secret has been consumed and Password Pusher reports that it has expired and is no longer available.

Opening the same link after the view limit shows an expired page, confirming the secret is no longer available

Step 8: Verify the one time semantics from the command line

The image ships a self test that proves the self destruct behaviour end to end over TLS. It pushes a one time secret through the JSON API, reads it once (returning the secret), then reads it again (returning expired with no payload):

sudo /opt/passwordpusher/passwordpusher-selftest.sh

The expected output confirms the round trip: the first read returns the secret and the second read reports the push expired.

The passwordpusher-selftest.sh output reporting round-trip OK with the first view served and the second view expired, proving one time self destruct over TLS

Step 9: Confirm TLS and inspect the per instance certificate

Confirm that plain HTTP redirects to HTTPS, that the web UI answers over TLS, and inspect the per VM self signed certificate:

curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://127.0.0.1/
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1/
sudo openssl x509 -in /etc/nginx/tls/passwordpusher.crt -noout -subject -ext subjectAltName

curl shows plain HTTP 80 returning a 301 redirect to https, the web UI returning HTTP 200 over TLS, and openssl printing the per VM self signed certificate subject and Subject Alternative Names

Step 10: Check the baked version and appliance info

The exact Password Pusher version and source commit baked into the image, along with the per VM appliance details, are recorded on the VM:

cat /opt/passwordpusher/VERSION
sudo cat /root/passwordpusher-info.txt

The /opt/passwordpusher/VERSION file showing the baked Password Pusher version, tag and source commit, and the per VM passwordpusher-info.txt describing the public URL and the loopback bound components

Step 11: How the appliance is wired

  • Password Pusher — a Ruby on Rails application at /opt/passwordpusher/app, run by passwordpusher.service on the puma web server as the unprivileged passwordpusher user, bound to 127.0.0.1:5100, serving both the web UI and the JSON API.

  • SQLite — a local database at /opt/passwordpusher/app/storage/db/production.sqlite3. Push payloads are encrypted at rest with a per VM key. No external database is required.

  • nginxnginx.service, terminating TLS on :443 and reverse proxying to Password Pusher, redirecting :80 to HTTPS, and serving an unauthenticated /healthz for load balancer probes.

  • First bootpasswordpusher-firstboot.service runs once on first boot: it generates the per VM session and payload encryption keys, regenerates the per VM self signed TLS certificate, starts the services, proves the one time round trip, and writes /root/passwordpusher-info.txt.

Step 12: Use your own domain and a trusted certificate (production)

The image ships a self signed certificate so it is secure out of the box, but browsers will warn on it. For production, point a DNS name at the VM and install a CA signed certificate. With your own domain you can obtain a free certificate from Let's Encrypt:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com

Certbot installs the certificate into nginx and sets up automatic renewal. Password Pusher builds share links from the host the browser used, so no application configuration change is needed when you move to your own domain.

Step 13: Managing the Password Pusher service

sudo systemctl restart passwordpusher
sudo journalctl -u passwordpusher.service --no-pager | tail -20

Adjust application behaviour (for example the default expiry, or enabling accounts) by editing the environment file /etc/passwordpusher/passwordpusher.env, then run sudo systemctl restart passwordpusher. See the Password Pusher documentation for the full list of PWP__ configuration variables.

Step 14: Security recommendations

  • Restrict SSH. Allow inbound 22 only from your management network; keep 443 (and 80 for the redirect) open to your users.

  • Install a trusted certificate. Replace the self signed certificate with a CA signed one (Step 12) so recipients are not trained to click through warnings.

  • Keep pushes short lived. The shortest expiry that still works for your recipients gives the smallest window of exposure. Both a day limit and a view limit apply by default.

  • Keep the image updated. Unattended security upgrades remain enabled so the OS keeps receiving patches.

  • Consider enabling accounts. The appliance ships anonymous by design. If you want per user audit logs and dashboards, you can enable the login system in /etc/passwordpusher/passwordpusher.env; choose a strong password when you create the first account.

Step 15: Support and Licensing

Password Pusher is open source software distributed under the Apache License 2.0. This image bundles the upstream Password Pusher release unmodified; the licence file is retained on the image under /opt/passwordpusher/. cloudimg packaging, hardening and support are provided by cloudimg.

Deploy on Azure

Find this image on the Azure Marketplace and deploy it in minutes. See www.cloudimg.co.uk for the full catalogue.

Need Help?

cloudimg provides 24/7 support with a guaranteed 24 hour response SLA. Contact us through www.cloudimg.co.uk for deployment assistance, configuration help or any questions about this image.