Piper Tts
Overview
Piper is a fast, local neural text-to-speech engine. It turns text into natural-sounding speech entirely on the CPU using ONNX Runtime, with no GPU and no external speech API. The text you synthesize never leaves your own network.
The SecureAnyCloud image installs Piper 1.5.0 in a dedicated Python virtual environment and runs its HTTP server as a systemd service bound to loopback. An nginx reverse proxy publishes the server on port 443 with TLS and HTTP Basic authentication. A unique credential is generated on the first boot of every VM, and one voice model is included and ready to speak immediately.
What you get:
- Piper 1.5.0 (GPL-3.0-or-later), installed unmodified from PyPI into
/opt/piper/venv - The
en_US-ljspeech-mediumvoice, preinstalled and ready to use (LJ Speech corpus, public domain, trained from scratch) - A browser interface and a JSON HTTP API that return 16-bit PCM WAV audio at 22050 Hz
- The Piper server bound to
127.0.0.1:5000only, never exposed directly to the network - nginx on port 443, terminating TLS with a certificate generated uniquely for each VM and enforcing bcrypt HTTP Basic authentication
- A unique admin password generated on first boot into a root-only credentials file, with no default login shipped
- The voice-download endpoint disabled, so the server cannot be induced to fetch files from the internet
/usr/local/lib/sac/piper-audio-check.py, a self-testing tool that verifies synthesized audio is real and not silence- The licence position for the engine and the voice, recorded on the VM at
/usr/share/doc/sac-piper/PIPER-LICENSE-NOTICE.txt piper.serviceandnginx.serviceas systemd units, enabled and active- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
- VM size: Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point. Piper is CPU-only, so no GPU VM size is needed or recommended.
- NSG inbound: allow
22/tcpfrom your management network and443/tcpfor the API and browser interface.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Piper TTS by SecureAnyCloud, 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 HTTPS (443). Then select Review + create, followed by Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:piper-tts-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name piper \
--image sac1647283583153:piper-tts-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku StandardThen open port 443 to the clients that need it:
az vm open-port --resource-group <your-rg> --name piper --port 443Step 3 - Confirm the services are running
SSH to the VM and confirm that both units are active. Piper itself listens only on 127.0.0.1:5000. nginx on :443 is the only network-facing surface.
systemctl is-active piper nginx ss -tln | grep -E ':5000|:443'Both units report active, and the listener on port 5000 is bound to 127.0.0.1, not to 0.0.0.0.
Step 4 - Retrieve the per-VM credential
A unique password is generated on the first boot of every VM and written to a file that only root can read. There is no default or shared login.
sudo cat /root/piper-credentials.txtThe file lists the URL, the voice, the username admin and the generated password, together with ready-to-run examples. Confirm that only root can read the file:
ls -l /root/piper-credentials.txtStep 5 - Open the browser interface
Browse to https://<vm-public-ip>/. The certificate is self-signed and generated uniquely for this VM, so your browser warns once. Accept the warning, or copy /etc/nginx/tls/piper.crt to your client's trust store. Sign in with admin and the password from Step 4.
Type a sentence into the text box, then select Speak. Piper synthesizes the sentence, and an audio player appears and begins playing the speech. The interface also reports how long synthesis took.
The open /health endpoint reports the loaded voice and the server's record of the most recent utterance. Use it to confirm the engine is working without sending any text.
Step 6 - Synthesize speech from the HTTP API
Send a POST to /synthesize with a JSON body that contains the text. The response body is a 16-bit PCM WAV file, mono, 22050 Hz. Run this on the VM itself:
PIPER_PASSWORD=$(sudo grep '^PIPER_PASSWORD=' /root/piper-credentials.txt | cut -d= -f2-)
curl -sS --cacert /etc/nginx/tls/piper.crt -u admin:"$PIPER_PASSWORD" \
-X POST https://127.0.0.1/synthesize \
-H 'Content-Type: application/json' \
-d '{"text":"The quick brown fox jumps over the lazy dog."}' \
-o /tmp/speech.wav file /tmp/speech.wavfile reports RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 22050 Hz.
From a client machine, use the VM's public address and the same credential:
curl -u admin:<password> --cacert piper.crt \
-X POST https://<vm-public-ip>/synthesize \
-H 'Content-Type: application/json' \
-d '{"text":"Hello from Piper."}' \
--output speech.wavControl the speaking rate with length_scale. Values above 1.0 are slower, and values below 1.0 are faster:
PIPER_PASSWORD=$(sudo grep '^PIPER_PASSWORD=' /root/piper-credentials.txt | cut -d= -f2-)
curl -sS --cacert /etc/nginx/tls/piper.crt -u admin:"$PIPER_PASSWORD" \
-X POST https://127.0.0.1/synthesize \
-H 'Content-Type: application/json' \
-d '{"text":"This sentence is spoken more slowly.","length_scale":1.3}' \
-o /tmp/slow.wav ls -l /tmp/slow.wavStep 7 - Verify the audio is real
A zero-length or completely silent WAV is still a structurally valid WAV, so the HTTP status code alone does not prove that speech was produced. The image ships a checker that inspects the waveform itself: its duration, RMS and peak amplitude.
/usr/local/lib/sac/piper-audio-check.py /tmp/speech.wav \
--min-duration 1 --min-rms 300 --min-peak 2000The checker prints the measured frames, duration, RMS and peak. It exits non-zero if the audio is silent or implausibly short. To confirm that the check is meaningful rather than always passing, run its self-test:
/usr/local/lib/sac/piper-audio-check.py --self-testThe self-test generates digital silence and a real waveform. It passes only if the checker rejects the first and accepts the second.
Step 8 - Confirm the security posture
The image is closed by default. Anonymous requests, wrong credentials and the voice-download endpoint are all refused. The health probe stays open for load balancers.
PIPER_PASSWORD=$(sudo grep '^PIPER_PASSWORD=' /root/piper-credentials.txt | cut -d= -f2-)
echo "anonymous : $(curl -s -o /dev/null -w '%{http_code}' --cacert /etc/nginx/tls/piper.crt -X POST https://127.0.0.1/synthesize -H 'Content-Type: application/json' -d '{"text":"hi"}')"
echo "wrong pass : $(curl -s -o /dev/null -w '%{http_code}' --cacert /etc/nginx/tls/piper.crt -u admin:wrong -X POST https://127.0.0.1/synthesize -H 'Content-Type: application/json' -d '{"text":"hi"}')"
echo "download : $(curl -s -o /dev/null -w '%{http_code}' --cacert /etc/nginx/tls/piper.crt -u admin:"$PIPER_PASSWORD" -X POST https://127.0.0.1/download -H 'Content-Type: application/json' -d '{"voice":"en_US-lessac-medium"}')"
echo "health : $(curl -s -o /dev/null -w '%{http_code}' --cacert /etc/nginx/tls/piper.crt https://127.0.0.1/healthz)"Anonymous synthesis and a wrong password both return 401, the download endpoint returns 403, and the health probe returns 200.
POST /download is deliberately disabled. Upstream, it makes the server fetch voice files from the internet on request. That is a server-side request forgery surface, and it lets unvetted voice models arrive on your disk.
Licence position
Two separate licences apply, and they are recorded on the VM at /usr/share/doc/sac-piper/PIPER-LICENSE-NOTICE.txt:
cat /usr/share/doc/sac-piper/PIPER-LICENSE-NOTICE.txtThe engine. Piper 1.5.0 is licensed GPL-3.0-or-later. Development moved from the original rhasspy/piper repository, which was archived in October 2025, to OHF-Voice/piper1-gpl. The current release is GPL, not MIT.
SecureAnyCloud ships Piper unmodified and adds no code into the Piper process. The authentication layer is a separate nginx process reached over loopback. The on-VM notice includes a written offer for the complete corresponding source.
The voice. This image ships exactly one voice, en_US-ljspeech-medium. It is built from the LJ Speech corpus, which its author states is in the public domain, and its model card records that it was trained from scratch rather than fine-tuned from another model.
The training lineage matters. Most Piper voices are fine-tuned from a small number of base voices, and two of the most common bases carry restrictions. The lessac base is trained on a corpus licensed for research only, whose terms explicitly exclude commercial speech-synthesis products. The ryan base is CC BY-NC-SA 4.0, which is non-commercial.
A fine-tuned voice's own model card describes only the fine-tuning data, so a voice can declare a permissive licence while inheriting a restricted base. Several voices declare CC0 or Apache-2.0 and are fine-tuned from lessac. The Hugging Face repository tag and voices.json are not reliable here either. The repository carries a single blanket mit tag that the individual model cards contradict, and voices.json has no licence field at all.
Adding another voice
You can install additional voices, but you are responsible for their licensing. Before using any voice commercially, read its MODEL_CARD and follow its "Finetuned from" line back to the root of the training lineage. A permissive licence line on the voice itself is not sufficient.
Voices whose full chain is public domain or permissive include en_US-ljspeech, en_GB-cori, en_US-kristin and en_US-norman. To install one, place both of its files in the voices directory and point the service at it:
sudo curl -fL -o /var/lib/piper/voices/en_GB-cori-medium.onnx \
https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_GB/cori/medium/en_GB-cori-medium.onnx
sudo curl -fL -o /var/lib/piper/voices/en_GB-cori-medium.onnx.json \
https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_GB/cori/medium/en_GB-cori-medium.onnx.json
sudo chown piper:piper /var/lib/piper/voices/en_GB-cori-medium.onnx*
sudo sed -i 's/^VOICE=.*/VOICE=en_GB-cori-medium/' /etc/piper/piper.env
sudo systemctl restart piper.serviceMaintenance
Piper and nginx are ordinary systemd units:
systemctl status piper.service --no-pager | head -5Logs go to the journal:
journalctl -u piper.service --no-pager | tail -5The image keeps unattended security upgrades enabled for the operating system. To change the served voice, edit VOICE in /etc/piper/piper.env and restart piper.service.
To rotate the API password, regenerate the htpasswd entry:
sudo htpasswd -B /etc/nginx/.piper.htpasswd admin
sudo systemctl reload nginxFor a production deployment, replace the self-signed certificate in /etc/nginx/tls/ with one issued for your own hostname, then reload nginx.
Support
SecureAnyCloud provides 24/7 technical support for this product by email and live chat. Support covers deployment, the HTTP API, voice selection and voice licensing, TLS and the per-VM credential, and scaling. Email sales@secureanycloud.com.
Deploy on Azure
Launch Piper TTS 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
This image runs Piper 1.5, the fast, local neural text-to-speech engine, on Ubuntu 24.04 LTS. Piper is installed into a dedicated Python virtual environment under /opt/piper on Python 3.12. An unprivileged piper system account runs it under a systemd service that starts the HTTP server on boot.
A high-quality English voice model (en_US-lessac-medium) is baked into the image. The server synthesises speech fully offline the moment it boots, and no model is fetched at first boot.
What you get:
- The server listens on the loopback address
127.0.0.1:5000, and nginx fronts it on port 80 with HTTP Basic Authentication. - A lightweight
/healthendpoint stays open for load balancers. Every synthesis request requires the password. - The default security group opens port 22 (SSH) and port 80 (HTTP) only, so port 5000 is never reachable externally and no text you synthesise leaves the instance.
- On the first boot of every deployed instance, a one-shot service generates a fresh password that is unique to that instance. It writes the password to
/root/piper-credentials.txt(mode0600, root only). No shared or default credentials ship in the image. - Voice models live at
/var/lib/piper/voiceson a dedicated, independently resizable EBS data volume. - 24/7 SecureAnyCloud support
Prerequisites
- An AWS account subscribed to this product in AWS Marketplace
- An EC2 key pair in your target region for SSH access
- A security group that allows inbound TCP 22 (SSH) from your IP address and TCP 80 (HTTP) from your users
- An instance type of
m5.largeor larger (recommended)
Connecting to your instance
Connect over SSH. On the Ubuntu 24.04 image, the login user is ubuntu. For example, run ssh -i your-key.pem ubuntu@<instance-public-ip>.
Step 1 - Launch from the AWS Marketplace console
- Open the product page in AWS Marketplace. Choose Continue to Subscribe, then Continue to Configuration.
- Select the Piper 1.5 on Ubuntu 24.04 delivery option and your region. Then choose Continue to Launch.
- Choose your instance type, VPC and subnet, key pair, and the security group described above. Then launch.
Step 2 - Launch from the AWS CLI
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name your-key \
--security-group-ids sg-xxxxxxxx \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=piper-tts}]'Step 3 - Connect to your instance
Connect over SSH with your EC2 key pair:
ssh -i your-key.pem ubuntu@<instance-public-ip>Step 4 - Confirm the services are running
Check that both services are active and that the health endpoint responds:
systemctl is-active piper-http.service nginx.service curl -s http://127.0.0.1/healthExpected output:
active active okStep 5 - Retrieve your password
Read the credentials file over SSH:
sudo cat /root/piper-credentials.txt# Piper TTS - generated on first boot by piper-firstboot.service PIPER_URL=http://<instance-public-ip>/ PIPER_USERNAME=admin PIPER_PASSWORD=<your-unique-password>HTTP Basic Authentication protects the synthesis API. Use the user admin and the password above. Only /health is open.
Step 6 - Synthesise speech over the HTTP API
The /synthesize endpoint accepts a POST with JSON {"text": "..."} and returns a WAV file. Read the per-instance password from the credentials file, then post some text:
PASS=$(sudo grep '^PIPER_PASSWORD=' /root/piper-credentials.txt | cut -d= -f2-)
curl -s -u "admin:$PASS" -X POST -H 'Content-Type: application/json' \
-d '{"text":"Hello from Piper, deployed by sac."}' \
-o /tmp/hello.wav http://127.0.0.1/synthesize file /tmp/hello.wavExpected output:
/tmp/hello.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 22050 HzFrom your own machine, send the same request to the instance's public IP on port 80, using HTTP Basic authentication with the user admin:
curl -u admin:<your-unique-password> -X POST -H 'Content-Type: application/json' \
-d '{"text":"Hello from Piper"}' -o hello.wav http://<instance-public-ip>/synthesizeOptional JSON fields include voice, speaker_id, length_scale (speaking rate), noise_scale and noise_w_scale. A request without valid credentials is rejected with 401 Unauthorized.
Step 7 - Confirm the runtime
Check the installed Piper version:
/opt/piper/venv/bin/pip show piper-tts | grep ^VersionVersion: 1.5.0Adding more voices
The default en_US-lessac-medium voice ships baked into the image. Download additional voices into the dedicated voice store on the data volume. Then reference them by name in the synthesis request, or set one as the server default:
sudo -u piper /opt/piper/venv/bin/python -m piper.download_voices en_GB-alba-medium \
--data-dir /var/lib/piper/voices
sudo systemctl restart piper-http.serviceBrowse the full voice catalogue in the Piper project's voice list. Each voice is an .onnx model and an .onnx.json config, both stored under /var/lib/piper/voices.
Enabling HTTPS
Install Certbot and request a certificate for your domain:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.comCertbot edits the nginx site at /etc/nginx/sites-available/sac-piper to add the TLS listener, and it arranges automatic renewal.
Backup and maintenance
- Voice models live under
/var/lib/piper/voiceson their own EBS volume. Snapshot that volume to back up any voices you have added. - The password is stored in the nginx htpasswd file
/etc/nginx/.piper.htpasswd. Rotate it withsudo htpasswd /etc/nginx/.piper.htpasswd admin. - Restart the service with
sudo systemctl restart piper-http.service. Read its logs withsudo journalctl -u piper-http.service.
Support
SecureAnyCloud provides 24/7 technical support for this image by email and chat. Support covers Piper deployment, adding and selecting voices, tuning synthesis parameters, backups, TLS termination and scaling. Contact details are on the AWS Marketplace listing.
Deploy on AWS
Launch Piper TTS on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com