Onetime Secret
Overview
This guide covers deploying and configuring Onetime Secret on Ubuntu 24.04 on Azure, using the SecureAnyCloud Azure Marketplace images. Onetime Secret is an open source, self-hosted service for sharing sensitive information safely. Instead of pasting a password into email or chat, where it lingers, you paste it into Onetime Secret and get back a one-time link. The recipient opens the link once to reveal the secret, after which it is permanently burned and the link stops working. Secrets also carry a time to live, so anything left unread expires on its own.
The image builds the latest stable Onetime Secret release reproducibly from source at build time. The exact version and source commit are recorded in /var/lib/onetimesecret/VERSION. Onetime Secret is a Ruby/Rack application served by Puma. It runs under systemd as the unprivileged onetime system user, bound to loopback only (127.0.0.1:3000). Secrets are stored in Redis, also bound to loopback (127.0.0.1:6379) and protected by a per-instance password. nginx is the sole network-facing surface. It terminates TLS on port 443 and reverse proxies to Puma.
The image is secure by default, with no known credential baked in. Every per-instance secret is generated on first boot only: the application root secret (from which all other cryptographic material is derived), the Redis password, and the colonel (administrator) account password. The colonel credentials and the per-VM connection details are written to a root-only file at /root/onetimesecret-info.txt. The core product, sharing a one-time secret, needs no login at all. The colonel account is the optional administrator.
What you get:
- The latest stable Onetime Secret release, built from source and run under systemd as the unprivileged
onetimesystem user - Puma bound to loopback only (
127.0.0.1:3000) and Redis bound to loopback (127.0.0.1:6379) with a per-instance password, so neither is exposed to the network - nginx terminating TLS on :443 and reverse proxying to the application, with HSTS and sensible security headers
- Port
:80returns a301redirect to HTTPS for every path except an unauthenticated/healthzendpoint (HTTP 200) for load balancer probes - A self-signed TLS certificate regenerated per VM on first boot (SAN includes the VM public IP and hostname). Replace it with your own CA-signed certificate for production
- A colonel administrator account created on first boot with a unique random password, plus a per-instance API token, both written to
/root/onetimesecret-info.txt - A built-in one-time self-test at
/opt/ots/onetimesecret-selftest.shthat proves the self-destruct semantics and the colonel credential end to end over TLS - Ubuntu 24.04 LTS base with the latest security patches applied at build time
- Azure Linux Agent for cloud integration and SSH key injection
- 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA
Prerequisites
Before you deploy this image, make sure you have:
- An Azure subscription with permission to deploy virtual machines
- An SSH key pair for administrative access to the VM as the
azureuseraccount - A Network Security Group that allows inbound TCP
443(HTTPS) and80(redirect) from the networks that should reach the service, and22(SSH) from your management network only - A VM size of Standard_B2s or larger (recommended)
Deploy from the Azure Portal
In the Azure Marketplace, find the Onetime Secret on Ubuntu 24.04 LTS by SecureAnyCloud image and select Create.
Choose your subscription, resource group and region.
Select a VM size (Standard_B2s or larger) and provide your SSH public key for the azureuser account.
On the Networking tab, allow inbound 443 and 80 from your users, and restrict 22 to your management network.
Review and create the VM. When the VM is running, browse to https://<your-public-ip>/.
Deploy from the Azure CLI
To deploy the same image from the Azure CLI, run the following command. Replace the resource group, location and image URN as needed:
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:onetimesecret-ubuntu-24-04:default:latest
az vm create \
--resource-group my-onetimesecret-rg \
--name onetimesecret \
--image sac1647283583153:onetimesecret-ubuntu-24-04:default:latest \
--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-onetimesecret-rg --name onetimesecret --port 443 --priority 1001
az vm open-port --resource-group my-onetimesecret-rg --name onetimesecret --port 80 --priority 1002Verify the Onetime Secret, Redis and nginx services
Connect over SSH as azureuser. Confirm that the three services are active, and that Puma and Redis are bound to loopback only, with nginx as the only public listener:
sudo systemctl is-active redis-server onetimesecret-web nginxss -tln | grep -E ':3000 |:6379 |:80 |:443 'The output shows onetimesecret-web (Puma) on 127.0.0.1:3000 and Redis on 127.0.0.1:6379 (both loopback only), while nginx listens on 0.0.0.0:80 and 0.0.0.0:443.
Open the Onetime Secret web interface
Browse to https://<your-public-ip>/. Because the certificate is self-signed and generated per VM, your browser warns about the certificate the first time. Accept the warning, or install your own certificate (see Step 12). The create a secret form opens. Paste a password, secret message or private link, optionally set a passphrase, and choose how long the secret lives before it expires on its own.
Create the secret and get a one time link
Select Create Link. Onetime Secret stores the secret and shows a one-time link that you can share with the recipient, along with a reminder to share the link separately from any other details. A timeline shows when the secret was created and when it will expire.
Reveal the secret once
When the recipient opens the link, Onetime Secret warns them that the secret is shown only once. After they choose to reveal it, Onetime Secret displays the secret with a copy button. This is the single permitted view.
Confirm the secret self destructs
Open the same link a second time to see the one-time guarantee in action. The secret has already been consumed and permanently deleted, so Onetime Secret reports that it has been viewed or has expired.
Verify the one time semantics from the command line
The image ships a self-test that proves the self-destruct behavior end to end over TLS. It creates a one-time secret through the API, reads it once (HTTP 200), reads it again (HTTP 404), and then confirms that the per-instance colonel credential authenticates against the API (200 with the real token, 401 with a wrong one):
sudo /opt/ots/onetimesecret-selftest.shThe expected output confirms the round trip and the credential check: firstReveal=200 secondReveal=404 and colonel API auth=200 wrongToken=401.
Confirm TLS and inspect the per instance certificate
Confirm that plain HTTP redirects to HTTPS and that the web UI and API answer over TLS. Then 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/onetimesecret.crt -noout -subject -ext subjectAltNameSign in as the colonel administrator
Onetime Secret creates a colonel (administrator) account on first boot with a unique random password. The email, password and a per-instance API token are written to a root-only file. View the built-in version and the per-VM appliance details with:
cat /var/lib/onetimesecret/VERSIONsudo cat /root/onetimesecret-info.txtTo sign in as the administrator, browse to https://<your-public-ip>/signin and enter the colonel email and the password from /root/onetimesecret-info.txt.
How the appliance is wired
Onetime Secret application: a Ruby/Rack app served by Puma. onetimesecret-web.service runs it as the unprivileged onetime user from /var/lib/onetimesecret, bound to 127.0.0.1:3000, serving both the API and the Vue web frontend.
Redis: redis-server.service is bound to 127.0.0.1:6379 and protected by a per-instance password, and it holds the secrets with their time to live. Onetime Secret requires Redis, so onetimesecret-web.service declares a dependency on it.
nginx: nginx.service terminates TLS on :443, reverse proxies to the application, redirects :80 to HTTPS, and serves an unauthenticated /healthz for load balancer probes.
First boot: onetimesecret-firstboot.service runs once on first boot. It rotates the Redis password, generates the application root secret, writes the per-VM configuration, regenerates the per-VM self-signed TLS certificate, creates the colonel administrator, proves the one-time round trip, and writes /root/onetimesecret-info.txt.
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 warn about 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>Certbot installs the certificate into nginx and sets up automatic renewal. When you move to your own domain, set the public hostname that Onetime Secret uses for its links by editing HOST in /var/lib/onetimesecret/.env (for example HOST=secrets.example.com), then run sudo systemctl restart onetimesecret-web.
Managing the Onetime Secret service
sudo systemctl restart onetimesecret-websudo journalctl -u onetimesecret-web.service --no-pager | tail -20Application settings are read from /var/lib/onetimesecret/.env (the root secret, the Redis URL, the public HOST and the colonel email). After changing that file, run sudo systemctl restart onetimesecret-web to apply it.
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 the colonel credentials safe. They live in /root/onetimesecret-info.txt (root only). Sign in once and change the password if you prefer, and treat the API token as a secret.
Keep secrets short-lived. The shortest expiry that still works for your recipients gives the smallest window of exposure. Every secret is one-time by design.
Keep the image updated. Unattended security upgrades remain enabled, so the OS keeps receiving patches.
Support and Licensing
Onetime Secret is open source software distributed under the MIT License. This image bundles the upstream Onetime Secret release built from source, and the license file is retained on the image under /opt/ots/LICENSE.txt. SecureAnyCloud provides the packaging, hardening and support.
Deploy on Azure
Find this image on the Azure Marketplace and deploy it in minutes. See secureanycloud.com for the full catalog.
Need Help?
SecureAnyCloud provides 24/7 support with a guaranteed 24 hour response SLA. Contact us through secureanycloud.com for deployment assistance, configuration help or any questions about this image.
Deploy on Azure
Launch Onetime Secret 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
Overview
Onetime Secret is an open source service for sharing sensitive information safely. A sender pastes a secret, such as a password, an API key or a private note, and receives a unique one-time link. The recipient opens that link exactly once to reveal the secret, after which it is permanently destroyed and the link returns not-found. Secrets can carry an optional passphrase and an expiry, so nothing lingers in inboxes or chat history.
This SecureAnyCloud image runs the Onetime Secret application under Puma, bound to the loopback address 127.0.0.1:3000. Redis, bound to 127.0.0.1:6379 with a password, backs the application. An nginx reverse proxy fronts both and terminates TLS on port 443. Port 80 redirects to HTTPS and serves an unauthenticated /healthz endpoint for load balancers.
A unique application secret, Redis password and administrator (colonel) account are generated on the first boot of every instance, so no shared or default credential ships in the image. The Redis secret store lives on a dedicated data volume mounted at /var/lib/redis. The image is backed by 24/7 SecureAnyCloud support.
What you get:
- Onetime Secret 0.26.1, built from source and managed by systemd, serving a full web UI over HTTPS
- nginx on port 443 terminating TLS with a self-signed certificate regenerated per instance, and port 80 redirecting to HTTPS
- The application bound to the loopback address
127.0.0.1:3000and Redis bound to127.0.0.1:6379, neither exposed to the network - Redis protected with a unique password, so the secret store is never reachable anonymously
- A unique application secret, Redis password and administrator account generated on first boot and recorded in a root-only file
- Open account self-registration disabled, with no reachable default administrator credential
- A dedicated data volume at
/var/lib/redisholding the Redis secret store redis-server.service,onetimesecret-web.serviceandnginx.serviceas systemd units, enabled and active- An unauthenticated
/healthzendpoint for load-balancer health checks - 24/7 SecureAnyCloud support
Prerequisites
Before you launch the AMI, make sure you have:
- An AWS account, an EC2 key pair in the target region, and a VPC with a public subnet
- The m5.large (2 vCPU / 8 GiB RAM) instance type, which is recommended
- A security group that allows inbound
22/tcpfrom your management network for SSH, and443/tcp(and optionally80/tcp, which only redirects to HTTPS) for the web UI
Step 1 - Launch the AMI
Subscribe to the listing in AWS Marketplace, choose Continue to Launch, and launch through the EC2 console or the AWS CLI.
Select the m5.large instance type, your key pair, and a security group that opens ports 22 and 443.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <your-key-pair> \
--security-group-ids <security-group-id> \
--subnet-id <subnet-id> \
--associate-public-ip-addressThe application, Redis and nginx start automatically. On the very first boot, a one-shot service generates the per-instance secrets, resolves the instance public address, regenerates the TLS certificate and proves the one-time round trip before the service is ready. Allow a minute or two after the instance reaches the running state.
Step 2 - Connect to your instance
Connect over SSH as the default login user for your OS variant.
OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> <login-user>@<public-ip>Step 3 - Confirm the services are running
Check that all three services report active.
systemctl is-active redis-server onetimesecret-web nginxExpected output:
active active activeStep 4 - Confirm the loopback bindings
The application and Redis must listen only on the loopback interface, never on a public address. nginx is the sole network-facing surface.
sudo ss -tlnp | grep -E ':3000|:6379'Expected output, with both bound to 127.0.0.1 only:
LISTEN 0 1024 127.0.0.1:3000 0.0.0.0:* LISTEN 0 511 127.0.0.1:6379 0.0.0.0:*Confirm that Redis rejects unauthenticated access. It requires the per-instance password:
sudo redis-cli pingExpected:
NOAUTH Authentication required.Step 5 - Verify the TLS endpoints
Port 80 redirects to HTTPS, and the web UI and the health endpoint answer over TLS. The certificate is self-signed per instance, so the command uses -k to skip verification from the command line.
curl -s -o /dev/null -w 'http :80 -> %{http_code} %{redirect_url}\n' http://127.0.0.1/
curl -sk -o /dev/null -w 'healthz -> %{http_code}\n' https://127.0.0.1/healthz
curl -sk -o /dev/null -w 'web UI -> %{http_code}\n' https://127.0.0.1/Expected:
http :80 -> 301 https://127.0.0.1/ healthz -> 200 web UI -> 200Step 6 - Read your per-instance details
On first boot, the image writes the service URL, the Redis password and the optional administrator (colonel) account to a root-only file. Read it with:
sudo cat /root/onetimesecret-info.txtIt contains these keys (values are unique to your instance):
ONETIMESECRET_URL=https://<public-ip>/ COLONEL_EMAIL=... COLONEL_PASSWORD=... COLONEL_API_TOKEN=... REDIS_PASSWORD=...Step 7 - Prove the one-time round-trip from the command line
The image ships a self-test. It creates a secret, reveals it once (HTTP 200), proves that a second reveal is refused (HTTP 404, because the secret has self-destructed), and checks the administrator API credential round trip.
sudo /opt/ots/onetimesecret-selftest.shExpected (keys will differ):
round-trip OK: created=... firstReveal=200 secondReveal=404 (one-time proven); colonel API auth=200 wrongToken=401Step 8 - Share a secret in the browser
Open https://<public-ip>/ in your browser. Because the certificate is self-signed per instance, accept the browser warning, or copy /etc/nginx/tls/onetimesecret.crt from the instance and trust it.
Paste a secret, optionally set a passphrase and an expiry, and select Create Link. The service returns a single-use link along with a timeline of when the secret was created and when it expires. Share this link separately from any other details.
Step 9 - Reveal once, then watch it self-destruct
When the recipient opens the link and confirms, the secret is revealed exactly once.
Open the same link a second time. The secret is gone, because it has been permanently destroyed.
Step 10 - Administrator sign-in (optional)
You can use Onetime Secret entirely anonymously. Creating and revealing secrets needs no account.
The optional administrator (colonel) account gives access to the admin dashboard and the API. Sign in at https://<public-ip>/signin with the COLONEL_EMAIL and COLONEL_PASSWORD from the info file. Open account self-registration is disabled on this image.
Step 11 - Confirm the dedicated data volume
The Redis secret store lives on its own EBS volume, separate from the OS disk and independently resizable.
df -h /var/lib/redis | tail -1Expected output, with a device distinct from the root filesystem mounted at /var/lib/redis:
/dev/nvme1n1 20G ... /var/lib/redisMaintenance
- Services: run
systemctl status redis-server onetimesecret-web nginx, andjournalctl -u onetimesecret-webfor application logs. - TLS: the per-instance certificate is at
/etc/nginx/tls/onetimesecret.crt. To use your own domain and certificate, terminate TLS at an Application Load Balancer, or replace the certificate and key and reload nginx. - Backups: snapshot the
/var/lib/redisdata volume with EBS snapshots or AWS Backup. - Version: the release built into the image is recorded at
/var/lib/onetimesecret/VERSION.
Support
24/7 technical support is available from SecureAnyCloud by email and chat at sales@secureanycloud.com. Support covers deployment, terminating TLS with your own domain and certificate, configuring expiry and passphrase policy, Redis backup planning, and integrating the Onetime Secret API into your workflows.
Deploy on AWS
Launch Onetime Secret with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com