
Deploy Morphos | (Just Updated) Self-Hosted File Converter API, PDF, Image, DOCX and EPUB, Locked With a Generated Password
Morphos file converter API, image, PDF, DOCX, EPUB, password-locked
morphos
Just deployed
Deploy and Host Morphos on Railway
Built for an LLM agent to deploy and use. The deploy form has no fields to fill: the whole converter sits behind a generated password, Railway's port is bound, and nothing needs a volume. Morphos is an open-source, self-hosted file converter with a web form and a REST API: it turns images, PDFs, Word and Excel documents and e-books into other formats on your own Railway project instead of on a third-party site, so an agent can convert a file with one request.
About Hosting Morphos
This template runs one service, morphos (the web form and the REST API on one public domain). It is stateless: each upload is converted in scratch space under /tmp and the result comes back in the response, so there is no volume and a redeploy loses nothing. The image bundles LibreOffice and calibre, so a conversion can take a while and the service wants a few GB of memory under load.
Locked down from boot. Upstream ships with no authentication at all, and every upload runs through LibreOffice or calibre on your Railway bill, so a public deploy would be an open conversion service for anyone who finds the URL. This template puts an nginx gateway in front of the app: every path except /health requires HTTP Basic auth with user admin and the password in MORPHOS_PASSWORD, a 32-character value generated per deploy. The wrapper refuses to start without a password of at least 16 alphanumeric characters. Uploads up to 512 MB are accepted. Upstream is Morphos v0.6.0, its last release (the repository was archived in 2024-11), pinned by digest.
Using it. Open https://YOUR_DOMAIN, sign in as admin with MORPHOS_PASSWORD (a browser prompts for it), pick a file and a target format. Hand the password only to people who should have access.
Agent contract
- Public URL:
https://RAILWAY_PUBLIC_DOMAIN(the generated domain of themorphosservice; the REST API is under/api/v1) - Private URL:
http://morphos.railway.internal:8080 - Credentials: the variable
MORPHOS_PASSWORDon themorphosservice; the user name is alwaysadmin - Auth: HTTP Basic,
curl -u "admin:$MORPHOS_PASSWORD". Without credentials, or with a wrong password, every path except/healthanswers401.GET /api/v1/formatslists the supported formats;POST /api/v1/uploadtakes multipart fieldstargetFormatanduploadFileand returns the converted file in the response body. - Health:
GET /healthreturns 200 (no credentials needed)
#!/bin/sh
# needs: RAILWAY_PUBLIC_DOMAIN, MORPHOS_PASSWORD (variables of the morphos service); also curl, base64. Stateless: writes only /tmp files.
B="https://$RAILWAY_PUBLIC_DOMAIN"
A="admin:$MORPHOS_PASSWORD"
# a 1x1 PNG, so the snippet needs no input file
echo 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==' | base64 -d | tee /tmp/morphos-in.png | wc -c
curl -s -o /dev/null -w "health: %{http_code}\n" "$B/health"
curl -s -o /dev/null -w "read without key: %{http_code}\n" "$B/api/v1/formats"
curl -s -o /dev/null -w "read with key: %{http_code}\n" -u "$A" "$B/api/v1/formats"
if curl -s -u "$A" "$B/api/v1/formats" | grep -q '"jpeg"'; then echo "formats list jpeg: ok"; else echo "formats list jpeg: FAILED"; fi
curl -s -u "$A" -F 'targetFormat=jpeg' -F 'uploadFile=@/tmp/morphos-in.png' "$B/api/v1/upload" --output /tmp/morphos-out.jpeg
if [ "$(head -c 3 /tmp/morphos-out.jpeg | od -An -tx1 | tr -d ' \n')" = "ffd8ff" ]; then echo "png to jpeg: ok"; else echo "png to jpeg: FAILED"; fi
curl -s -o /dev/null -w "write without key: %{http_code}\n" -F 'targetFormat=jpeg' -F 'uploadFile=@/tmp/morphos-in.png' "$B/api/v1/upload"
curl -s -o /dev/null -w "write with wrong key: %{http_code}\n" -u "admin:wrong" -F 'targetFormat=jpeg' -F 'uploadFile=@/tmp/morphos-in.png' "$B/api/v1/upload"
A fresh deploy prints health: 200, read without key: 401, read with key: 200, formats list jpeg: ok, png to jpeg: ok, write without key: 401 and write with wrong key: 401.
Why Deploy Morphos on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying Morphos on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
- Agent-ready - no deployer fields, a contract block and one script that proves a real conversion and the refusal of requests with no or a wrong password.
- Not an open converter - upstream has no login; the gateway adds one before anything is reachable.
- Private conversions - files go to your own deploy, not to a free converter site.
- Stateless - nothing to back up and nothing lost on redeploy.
- Pinned - the upstream image is pinned by digest and the wrapper by tag and digest.
Common Use Cases
- Agent file handling - give an agent one authenticated endpoint to turn a DOCX into PDF, a PDF into PNG pages, or a WEBP into JPEG before it reads the file.
- Private document conversion - convert contracts, scans and spreadsheets (DOCX, XLSX, CSV, PDF) without uploading them to a public converter.
- Pipeline step - call
POST /api/v1/uploadfrom a script or workflow engine to normalise incoming files. - Team converter - one shared instance behind a password for people who convert files every day.
Dependencies for Morphos Hosting
- The morphos service created by the template. A custom domain is optional.
Deployment Dependencies
Template Content
