Belenios
Overview
Belenios is an open-source verifiable online voting system developed by INRIA. Voters cast encrypted ballots, and anyone can check that a ballot was recorded on the public bulletin board. The final tally can be independently verified against that board, so results are trustworthy without having to trust the server.
Belenios separates roles cleanly: the administrator runs the election, the credential authority issues voting credentials, and the trustees share the decryption key.
This SecureAnyCloud image runs the Belenios server, built from the official release, behind nginx over HTTPS. The server is published on the loopback interface only, and nginx terminates TLS in front of it.
What you get:
- Belenios 3.3.0, built from the official INRIA release on top of the upstream
glondu/beleniosbasetoolchain, baked into the image and published on loopback127.0.0.1:8001 - nginx terminating TLS on
:443in front of Belenios, with:80redirecting to HTTPS - A per-VM administrator account generated on first boot. No default or shared credential ships in the image: Belenios ships with no accounts at all, and a single administrator is seeded uniquely for your VM.
- A self-contained, single-VM deployment. The election spool, accounts and password database live under
/var/lib/belenios. docker.service,belenios.serviceandnginx.serviceas systemd units, enabled and active- 24/7 SecureAnyCloud support
Belenios is distributed under the GNU AGPL-3.0-or-later licence, with an OpenSSL linking exception.
Secure by default: a per-VM administrator credential
This image ships with no default or shared login. Belenios itself ships with no accounts, and no password database ships in the image.
On first boot, a one-shot service resolves your public URL, generates a per-VM TLS certificate and writes the public election URL into the server configuration. It then seeds a single administrator account with a unique per-VM password, which it writes to a root-only file.
The Belenios server is deliberately held back until that has happened, so a fresh VM is never reachable with a well-known login. You retrieve the password over SSH and change it after your first login.
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting size. Scale up for very large electorates.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network, and 80/tcp and 443/tcp from wherever your administrators and voters browse Belenios. Port :80 only redirects to :443.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Belenios 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), HTTP (80) and HTTPS (443).
Select Review + create, then 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:belenios-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name belenios \
--image sac1647283583153:belenios-ubuntu-24-04:default:latest \
--size Standard_B2s \
--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 belenios --port 80 --priority 1010
az vm open-port --resource-group <your-rg> --name belenios --port 443 --priority 1020Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>The message of the day shows your VM's Belenios admin URL and the administrator username.
Step 4 - Confirm the services are running
Belenios runs as three systemd units: the Docker engine, the Belenios server and nginx. Check that all three are active:
systemctl is-active docker.service belenios.service nginx.serviceactive active activeThe Belenios server is published only on the loopback interface. nginx is the only service bound to public ports (:80 and :443):
sudo ss -tln | grep -E ':(80|443|8001) 'LISTEN 0 4096 127.0.0.1:8001 0.0.0.0:* LISTEN 0 511 0.0.0.0:443 0.0.0.0:* LISTEN 0 511 0.0.0.0:80 0.0.0.0:*The web UI is served over HTTPS, and plain HTTP redirects to it:
curl -sk -o /dev/null -w 'https:// -> %{http_code}\n' https://127.0.0.1/
curl -s -o /dev/null -w 'http:// -> %{http_code}\n' http://127.0.0.1/https:// -> 200 http:// -> 301Step 5 - Read the per-VM administrator credential
On first boot, the VM writes a root-only file with your Belenios URL, the administrator username and the unique password generated for this VM. Read it as root:
sudo grep -E '^BELENIOS_URL=|^BELENIOS_ADMIN_USER=|^BELENIOS_ADMIN_EMAIL=' /root/belenios-credentials.txtBELENIOS_URL=https://<vm-public-ip> BELENIOS_ADMIN_USER=admin BELENIOS_ADMIN_EMAIL=admin@sac.localThe BELENIOS_ADMIN_PASSWORD line in that file holds your unique password. Only the per-VM credential authenticates, and a wrong password is rejected.
The commands below print the HTTP status of the server's programmatic login endpoint, first for the per-VM password and then for a wrong one:
P=$(sudo grep '^BELENIOS_ADMIN_PASSWORD=' /root/belenios-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'per-VM password -> HTTP %{http_code}\n' -X POST https://127.0.0.1/api/login/local \
-H 'Content-Type: application/json' --data "{\"username\":\"<belenios-admin-user>\",\"password\":\"<belenios-admin-password>\"}"
curl -sk -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' -X POST https://127.0.0.1/api/login/local \
-H 'Content-Type: application/json' --data '{"username":"admin","password":"wrong-nope"}'per-VM password -> HTTP 200 wrong password -> HTTP 403Step 6 - First login
Open Belenios in your browser, then choose local login. Accept the self-signed certificate warning, or install a trusted certificate first (see "Enabling a trusted TLS certificate" below):
https://<vm-public-ip>/adminEnter the administrator username (admin) and the BELENIOS_ADMIN_PASSWORD from Step 5. Accept the terms of service on first login, and you reach the administration home.
After your first sign-in, change your password from your account menu.
Step 7 - Create a verifiable election
From the administration home, choose Create a new election and give it a name. Then work through the setup:
- Define your question(s) and answers.
- Add your voters by email.
- Let the credential authority generate voting credentials.
- Confirm the trustee setup.
- Open the election for voting.
Each election gets its own page with a cryptographic fingerprint, the list of trustees whose keys are needed to decrypt the result, and a See accepted ballots link. This is the public audit and verification surface that makes the result independently checkable.
Voters open the election link and vote in the booth. They enter their credential, answer the question, review and encrypt their ballot, authenticate, and confirm. The browser encrypts the ballot before it is ever sent to the server.
Step 8 - The Belenios server image
Belenios runs from a pinned image built at capture time from the official INRIA release. The image is baked into the VM, so nothing is pulled at runtime, and it is published on the loopback interface only:
sudo docker ps --format 'table {{.Image}}\t{{.Status}}\t{{.Ports}}'IMAGE STATUS PORTS belenios:3.3.0 Up 6 minutes 127.0.0.1:8001->8001/tcpVoter email (credentials and notifications)
Belenios sends voters their credentials and notifications by email. By default, this image queues outgoing mail to a log (/var/lib/belenios/var/log/outgoing-mail.log). The server never blocks on delivery, and you can inspect exactly what would be sent.
For production, wire a real SMTP relay. Drop an executable sendmail-compatible relay at /var/lib/belenios/relay-sendmail, for example an msmtp wrapper configured with your provider. Set your own domain in /var/lib/belenios/ocsigenserver.conf.in, then restart Belenios with sudo systemctl restart belenios.
Security updates
The image is patched at build time, including Ubuntu phased updates, and unattended-upgrades stays enabled, so security patches keep arriving on your VM. There should be no held-back packages:
apt-mark showholdYour data
Belenios stores its election spool, accounts and password database under /var/lib/belenios:
sudo du -sh /var/lib/belenios/varThe election spool holds cryptographic material for every election. To back up your elections, snapshot the VM's OS disk in Azure, or copy /var/lib/belenios/var to external storage on a schedule.
Enabling a trusted TLS certificate
The image ships a per-VM self-signed certificate so HTTPS works out of the box. Browsers warn until you install a trusted certificate.
Election URLs are cryptographically baked into election data, so install a trusted certificate before you create real elections.
Point a DNS A record at the VM's public IP and ensure 443/tcp is open in the NSG. Then install certbot and let it manage the nginx certificate. Substitute your own domain and email for the example values in the commands:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com -m you@example.com --agree-toscertbot configures the HTTPS server block and sets up automatic renewal. After it completes, set the <public-url prefix="https://your-domain.example.com"/> line in /var/lib/belenios/ocsigenserver.conf.in and run sudo systemctl restart belenios. Belenios is then available at your domain with a trusted certificate.
Upgrading Belenios
Belenios runs from a pinned image. SecureAnyCloud publishes updated images as new Belenios releases are certified. To migrate, deploy the new image and restore /var/lib/belenios/var. Always snapshot the OS disk first. SecureAnyCloud support can help you plan and perform upgrades.
Support
SecureAnyCloud provides 24/7 support for this image, covering deployment, upgrades, SMTP integration, TLS termination and election administration. Contact us by email or chat.
Belenios is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on Azure
Launch Belenios 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