Transmute on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Transmute on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Transmute is an open source, self-hosted file converter and compressor with a browser interface. You drop in a file, pick a target format and download the result: images, video, audio, documents, spreadsheets, ebooks, subtitles, 3D meshes, fonts and archives are all handled, across thousands of format pairs. Everything runs on your own instance, so the files you convert never leave your Azure subscription and are never uploaded to a third party service.
The cloudimg image ships the free and open source, MIT licensed Transmute application, run the officially supported way as the upstream container pinned by image digest. The container is captured into the VM, so your instance starts in seconds rather than pulling a multi gigabyte image on first boot. Upstream Transmute grants administrator rights to whoever creates the first account, and accepts that request with no authentication while the account list is empty, which is a real risk for a VM with a public IP. This image closes that window completely: on first boot, before the public port is ever opened, the instance generates a per-VM signing key and claims the administrator account itself with a per-VM random password, written to a root-only file. Backed by 24/7 cloudimg support.
Transmute is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Transmute project. It ships the free and open source self-hosted software, unmodified.

What is included:
- Transmute v2.0.0 (the MIT licensed self-hosted file converter), pinned by image digest
- A complete, fully redistributable conversion toolchain inside the image: ffmpeg, Ghostscript, Inkscape, Tesseract OCR, LibreOffice, Pandoc, Calibre and Draw.io
- Docker Engine running the application container with the app published to loopback only
- Host nginx as the single public listener on port
80, with a 1 GB upload cap and streaming uploads transmute.service,transmute-firstboot.serviceandtransmute-postboot.serviceas systemd units, enabled and active on boot- A per-VM administrator password and a per-VM token signing key, generated on first boot and never baked into the image
- The administrator account claimed during bootstrap while port
80is still closed, so a passer-by can never claim the instance - Anonymous and guest conversions disabled by default, so an open converter is never exposed to the internet
- Automatic clean up of uploaded and converted files on a configurable retention window
- No default login, no shipped secret, no bundled API key and an empty database on first boot
- 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
- Active Azure subscription, SSH public key, VNet + subnet in target region
- Subscription to the Transmute listing on Azure Marketplace
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a person or a small team converting images, audio and documents. Video transcoding is CPU bound and benefits from more cores, so for regular video work or several concurrent users use Standard_D4s_v5 or larger. Conversions are written to the VM's disk before download, so size the OS disk for the largest files you expect to handle. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web app from the networks that use it.
Step 1: Deploy from the Azure Portal
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Transmute by cloudimg, 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 HTTP (80). Then Review + create and Create.
Step 2: Deploy from the Azure CLI
RG="transmute-prod"; LOCATION="eastus"; VM_NAME="transmute-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/transmute/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name transmute-vnet --address-prefix 10.100.0.0/16 --subnet-name transmute-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name transmute-nsg
az network nsg rule create -g "$RG" --nsg-name transmute-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name transmute-nsg --name allow-http --priority 110 \
--destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name transmute-vnet --subnet transmute-subnet --nsg transmute-nsg --public-ip-sku Standard
Replace <sub-id> and <version> with your subscription id and the image version shown on the listing, and <your-mgmt-cidr> with the network you administer from.
Step 3: First boot and per-instance credentials
On the first boot of each VM, Transmute generates its own per-instance secrets and claims its own administrator account before the web port is opened. Nothing is baked into the image. Give the instance a minute after first boot, then SSH in and read the credentials file (it is 0600 root:root):
sudo cat /root/transmute-credentials.txt

The file contains everything unique to this instance:
TRANSMUTE_USERNAME/TRANSMUTE_PASSWORD— the administrator login you use in the web UI. The administrator has full access, including user management.TRANSMUTE_URL— the web address of this instance, resolved from its public IP on first boot.
A per-VM token signing key is written alongside them in /opt/transmute/.env, also 0600 root:root. It is generated on this VM and never exists in the image. Persisting it matters: upstream generates a fresh random key in memory whenever the variable is empty, which would silently sign everyone out every time the container restarted.
Confirm the services and container are healthy:
sudo systemctl is-active docker transmute-firstboot transmute transmute-postboot nginx
active
active
active
active
active
sudo docker compose -f /opt/transmute/docker-compose.yml ps --format 'table {{.Service}}\t{{.Status}}\t{{.Ports}}'
SERVICE STATUS PORTS
transmute Up 52 seconds (healthy) 127.0.0.1:3313->3313/tcp
The application container publishes to loopback only; host nginx on port 80 is the single public door.
Step 4: The security model
A file converter reachable on a public IP is an attractive target: it accepts arbitrary uploads, it spends CPU and disk on them, and media parsers are a classic memory safety attack surface. This image is therefore locked down by default in four ways.
The administrator seat is already taken. Upstream Transmute makes the first account an administrator and accepts that request with no authentication while the account list is empty. transmute-postboot.service claims it first, over the loopback port, with a password generated for this VM. Afterwards the same endpoint refuses forever, which is enforced by the application's own code rather than by a configuration flag.
The public port is closed during bootstrap. Host nginx, the only public listener, does not start until the administrator exists: it is gated on a bootstrap-ready marker that post-boot creates only after the account has been claimed. Port 80 is therefore closed for the whole bootstrap window, so there is no moment in which a stranger could claim the instance.
Nothing is anonymous. Guest and unauthenticated conversions ship disabled, so every upload and every conversion requires a login. There is no open self-registration either: once the administrator exists, creating further accounts requires an administrator token.
The app is not directly exposed. The application listens on 127.0.0.1:3313 only. nginx caps a single upload at 1 GB and streams request bodies rather than spooling them into memory.
ss -tln | grep -E ':(80|3313) ' | awk '{print $1, $4}'
LISTEN 0.0.0.0:80
LISTEN 127.0.0.1:3313
LISTEN [::]:80
Every one of those claims is checked at runtime rather than asserted. You can reproduce the checks yourself:
curl -s -o /dev/null -w 'GET /api/files -> %{http_code}\n' http://127.0.0.1/api/files
curl -s -o /dev/null -w 'POST /api/guest/session -> %{http_code}\n' -X POST http://127.0.0.1/api/guest/session
curl -s http://127.0.0.1/api/users/bootstrap-status; echo
GET /api/files -> 401
POST /api/guest/session -> 403
{"requires_setup":false,"user_count":1}
An anonymous file listing is refused, guest sessions are refused, and the instance reports that setup is complete with exactly one account: the administrator claimed for this VM.

Step 5: Sign in and convert a file
Open http://<public-ip>/ in a browser. You are sent to the sign in page, because nothing on this instance is public.

Sign in with the TRANSMUTE_USERNAME and TRANSMUTE_PASSWORD from the credentials file. You land on the Workspace, which is the converter. Drop a file onto the drop zone or click to browse, then pick the target format on the file's row and choose a quality preset.

Click Convert. When the job finishes, the file moves to Completed and the download, preview and delete actions appear on its row.

The Jobs page keeps the history of everything this instance has converted, with the resulting format, size and status for each job. Both image and audio conversions are shown here, the latter handled by the ffmpeg pipeline inside the image.

The preview action renders the file in the browser without downloading it, so you can check a result before saving it.

Files can also be pulled in by URL rather than uploaded, using the URL for Transmute to grab field on the workspace. That fetch is made by the instance itself, so point it only at sources you trust.
Step 6: Verify a real conversion from the command line
The image ships a prover that drives the whole product through the public front door and checks the output's magic bytes, not merely that a request returned HTTP 200. It uploads a generated PNG and converts it to JPEG, then uploads a generated WAV and converts it to FLAC through ffmpeg, asserting the downloaded bytes really are a JPEG and really are a FLAC.
sudo /usr/local/sbin/transmute-roundtrip.sh
OK round-trip: url=http://<public-ip>/ user=admin; ready=200; anon /api/files 401; admin seat taken (POST /api/users 401); guest 403; wrong password 401; login 200 + JWT; PNG->JPEG output magic ffd8ff (1039 bytes); WAV->FLAC output magic fLaC via ffmpeg
ffd8ff is the JPEG start-of-image marker and fLaC is the FLAC stream marker, so both conversions genuinely produced files in the requested format.
Step 7: The conversion toolchain and its licensing
Transmute delegates to a set of well known open source tools, all of which ship inside the image. Because a converter's dependency stack is where redistribution problems usually hide, the image records the exact inventory it was built with, and the build refuses to proceed if the bundled ffmpeg is a non-redistributable one.
sudo docker exec transmute ffmpeg -hide_banner -version | head -1
ffmpeg version 7.1.5-0+deb13u1 Copyright (c) 2000-2026 the FFmpeg developers
sudo sed -n '7,15p' /usr/share/doc/transmute/MEDIA-STACK.txt
Media + document tooling inside the image (all redistributable):
ffmpeg 7:7.1.5-0+deb13u1
ghostscript 10.05.1~dfsg-1+deb13u1
inkscape 1.4-6
libreoffice-impress 4:25.2.3-2+deb13u5
tesseract-ocr 5.5.0-1+b1
unrar-free 1:0.3.1-1
ffmpeg banner: ffmpeg version 7.1.5-0+deb13u1 Copyright (c) 2000-2026 the FFmpeg developers
ffmpeg build : verified NOT --enable-nonfree, and free of libfdk-aac.

The full inventory, with the licence of each component, is at /usr/share/doc/transmute/MEDIA-STACK.txt, and the upstream MIT licence is at /usr/share/doc/transmute/LICENSE. ImageMagick is deliberately absent: upstream removes it and its libraries from the image, and the image conversion path uses Pillow and PyMuPDF instead.
Step 8: Retention, users and day to day operation
Uploaded and converted files are cleaned up automatically so a busy instance does not fill its disk. The retention window is set per account from the Settings page and defaults to 60 minutes; raise it if you want results to linger, or lower it if you are handling sensitive material. Deleting a file from the Files or Jobs page removes it immediately.
Additional users are created from the account menu by the administrator. There is no open self-registration, so nobody can create an account on your instance without you.
Everyday service management is ordinary systemd:
sudo systemctl restart transmute
sudo systemctl status transmute --no-pager | head -5
Application logs come from the container:
sudo docker logs --tail 20 transmute
If you reach the VM by a DNS name rather than its IP address, set APP_URL in /opt/transmute/.env to that URL and restart the service so that links the application generates match how people actually reach it.
Troubleshooting
The web page does not load. Check that nginx is running and that the NSG allows 80/tcp from your network. On the very first boot, nginx deliberately stays down until the administrator account has been claimed, which takes a few seconds; sudo systemctl is-active transmute-postboot reporting active means bootstrap finished.
A conversion fails for one particular file. Not every format pair is supported in both directions, and some source files are simply malformed. The Jobs page records the failure against the job; sudo docker logs --tail 50 transmute shows the underlying tool's error.
Large uploads are rejected. nginx caps a single upload at 1 GB. Raise client_max_body_size in /etc/nginx/sites-available/transmute.conf and run sudo systemctl reload nginx if you need more, keeping the VM's disk size in mind.
Video conversions are slow. Transcoding is CPU bound and there is no GPU in the recommended size. Move to a compute optimised VM size for regular video work.
Support
cloudimg provides 24/7 support with a guaranteed 24 hour response SLA for this image: support@cloudimg.co.uk. Questions about Transmute itself belong upstream at github.com/transmute-app/transmute.