Self-Hosting OS-APS
Hosted demo
We operate a reference instance at os-aps.sciflow.net that always tracks the latest stable container images.
A development build is available at os-aps-next.sciflow.net. Use it to preview upcoming changes; it may be unstable.
Intended audience
This guide targets technical university IT and library teams who want to operate their own instance of the editor. If you are an author or publisher looking for a hosted solution, visit sciflow.net instead. We are also working on a hosting service for OS-APS - stay tuned.
Questions are welcome in the #development
channel on Slack.
Recommended deployment in brief
- Mirror the template repository published under
os-aps/community
on GitLab and keep it in sync with your institutional Git service. - Mount a dedicated, read-only font volume and point
FONT_PATH
to it so your exports use your university's typography. - Store manuscripts and uploads in an S3 bucket with versioning and automated backups instead of relying solely on a Docker volume.
- Run the application through Docker Compose (or your orchestrator of choice) behind a reverse proxy that terminates TLS for your institutional domain.
This guide assumes you are part of a university IT or library team and are comfortable operating Linux servers, Docker, Git, and S3-compatible storage.
Quick start – local evaluation
Need a quick look at OS-APS before investing in the full setup? You can run a self-contained demo in a few minutes. The container ships with the default export templates and downloads required open-source fonts on first start, so no additional assets are needed.
mkdir osaps-demo && cd osaps-demo
docker run \
--rm \
-p 127.0.0.1:3000:3000 \
--name os-aps-demo \
-v "$(pwd):/data" \
-e LOCAL_STORAGE_PATH=/data/manuscripts \
-e INSTANCE_TITLE="OS-APS Demo" \
registry.gitlab.com/sciflow/development/server:latest
- Using PowerShell instead of a Unix shell? Replace
$(pwd)
with${PWD}
and either place the command on one line or use backticks (\
) for line continuations. - Browse to http://localhost:3000 and create an administrator account when prompted.
- Press
Ctrl+C
to stop the container. Your manuscripts and configuration stay in theosaps-demo
directory so you can restart later. - Optional: add
-e FONT_PATH=/data/fonts
and drop fonts into./fonts
if you want to test custom typography, or run the image transformation sidecar for WMF/EMF support.
Once you are ready to go beyond local testing, proceed with the production-oriented steps below.
Production
Prerequisites
- A Linux host (or VM) with Docker Engine 24+ and the Docker Compose plugin installed.
- Git access to the
os-aps/community
group on GitLab. The repositories are public (MIT-licensed), so read access works anonymously; add a deploy key or token only if your automation needs write access or mirrors into a private namespace. - An institutional Git service (GitLab, Gitea, GitHub Enterprise, …) where you can host your customized template repository.
- An S3-compatible endpoint (AWS S3, MinIO, or on-prem object storage) where you can create buckets with versioning and lifecycle policies.
- DNS control for the domain you want to publish (e.g.
aps.university.edu
) and an option to obtain TLS certificates. - Optional: network access to SMTP, institutional SSO, logging or monitoring stacks if you plan to integrate them after the base install.
Step 1 – Prepare your template repository
The easiest way to stay current with template updates is to start from a community repository. You can mirror it into your institutional Git platform, but we encourage universities to collaborate directly under the os-aps/community
umbrella so improvements remain available to everyone. You can also copy templates from the source code at /templates. These are the templates that ship with every instance of the software.
- Request a repository in the
os-aps/community
group (or create one if you have permission). Alternatively, create an empty project in your institutional Git service, for examplegit@git.university.edu:press/os-aps-templates.git
. - On an administration workstation, create a bare mirror of the community repository:
git clone --mirror https://gitlab.com/os-aps/community/templates.git
cd templates.git
git remote add campus git@git.university.edu:press/os-aps-templates.git
git push --mirror campus
git remote rename origin upstream
git fetch upstream
git push --mirror campus
Automate template sync
Run git-sync
from a scheduled job or as a sidecar to keep your volume current. Example for a one-shot sync into a named Docker volume:
docker volume create osaps-templates
docker run --rm \
-v osaps-templates:/git \
registry.k8s.io/git-sync/git-sync:v4.1.0 \
--repo=git@git.university.edu:press/os-aps-templates.git \
--branch=main \
--root=/git \
--link=. \
--one-time
Adjust the repository URL to your internal mirror. Use SSH keys or tokens that provide read-only access.
Once the volume is ready, the application can mount it read-only and expose the templates via TEMPLATE_SOURCE=/templates
.
Step 2 – Prepare font assets
Document exports look best if they use the same fonts as your institutional publications.
- Collect the font files (OTF or TTF) that you have the right to distribute.
- Store them in a dedicated directory or Docker volume so they can be mounted read-only into the container.
- Point
FONT_PATH
at that mount (e.g./fonts
).
Example initialization:
docker volume create osaps-fonts
# Copy your font files into the volume (replace /mnt/fonts with your source)
docker run --rm -v osaps-fonts:/fonts -v /mnt/fonts:/source busybox cp /source/*.ttf /fonts/
By separating fonts into their own volume you can keep licensing under control and audit which font versions are in use.
Step 3 – Configure durable storage
We strongly recommend storing manuscripts and uploads in S3-compatible object storage with versioning and backup policies. This protects research output against operator error and ransomware and simplifies scaling across hosts.
- Create a bucket dedicated to OS-APS (for example
os-aps-manuscripts
). - Enable versioning on the bucket. With AWS you can run:
aws s3api put-bucket-versioning \
--bucket os-aps-manuscripts \
--versioning-configuration Status=Enabled
cat <<'JSON' > lifecycle.json
{
"Rules": [
{
"ID": "Archive old versions",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"NoncurrentVersionTransition": {"NoncurrentDays": 30, "StorageClass": "GLACIER"},
"NoncurrentVersionExpiration": {"NoncurrentDays": 365}
}
]
}
JSON
aws s3api put-bucket-lifecycle-configuration \
--bucket os-aps-manuscripts \
--lifecycle-configuration file://lifecycle.json
If you cannot use S3, mount a persistent volume (/var/opt/osaps
) and back it up with your existing tooling, but note that you lose automatic versioning.
Step 4 – Define the application stack
The following Docker Compose file demonstrates a production-friendly layout with separate volumes for application data, templates, and fonts, plus S3 configuration.
version: "3.9"
services:
osaps:
image: registry.gitlab.com/sciflow/development/server:latest
container_name: os-aps
restart: always
ports:
- "127.0.0.1:3000:3000"
environment:
INSTANCE_TITLE: "University Press"
INSTANCE_URL: "https://aps.university.edu"
LOG_LEVEL: info
LOCAL_STORAGE_PATH: /var/opt/osaps/manuscripts
TEMPLATE_SOURCE: /templates
FONT_PATH: /fonts
S3_ENDPOINT: "https://s3.example.edu"
S3_REGION: "eu-central-1"
S3_ACCESS_KEY: "${OSAPS_S3_ACCESS_KEY}"
S3_SECRET_KEY: "${OSAPS_S3_SECRET_KEY}"
S3_IMPORTER_BUCKET: "os-aps-manuscripts"
volumes:
- osaps-data:/var/opt/osaps
- osaps-templates:/templates:ro
- osaps-fonts:/fonts:ro
volumes:
osaps-data:
osaps-templates:
external: true
osaps-fonts:
external: true
Save the file as docker-compose.yml
. Store sensitive values such as S3_ACCESS_KEY
and S3_SECRET_KEY
in an .env
file next to it (the Compose plugin loads it automatically).
Environment variables of note
INSTANCE_TITLE
: Label displayed in the UI header.INSTANCE_URL
: Public base URL. Set it once your reverse proxy is ready so sessions and links use the official domain.LOCAL_STORAGE_PATH
: Used for temporary working files and cached exports. It should live on a persistent volume even when S3 is configured.TEMPLATE_SOURCE
: Path inside the container that points to your template volume.FONT_PATH
: Directory with the mounted fonts.S3_*
: Connection details for your object storage. Leave them unset only for evaluation deployments that rely on local storage.TRANSFORM_IMAGE_URL
: Optional URL of the transformation sidecar (see below) when you need WMF/EMF support.
Step 5 – Launch and verify
- Start the stack:
docker compose up -d
- Follow the logs during the first startup:
docker compose logs -f
- When the app reports
Server started on port 3000
, accesshttp://localhost:3000
(or your reverse proxy URL) and create the first administrator account. - Upload a template-managed manuscript and confirm that exports pick up your custom templates and fonts.
- Verify that objects appear in your S3 bucket and that versioning creates multiple revisions when you overwrite files.
Keeping templates synchronized on the server
If you prefer to keep everything contained on the host, schedule git-sync
as a systemd timer, cron job, or container:
cat <<'EOF' | sudo tee /etc/systemd/system/osaps-template-sync.service
[Unit]
Description=Sync OS-APS templates
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/docker run --rm \
-v osaps-templates:/git \
registry.k8s.io/git-sync/git-sync:v4.1.0 \
--repo=git@git.university.edu:press/os-aps-templates.git \
--branch=main \
--root=/git \
--link=.
EOF
Add a companion timer and reload systemd:
cat <<'EOF' | sudo tee /etc/systemd/system/osaps-template-sync.timer
[Unit]
Description=Schedule OS-APS template sync
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now osaps-template-sync.timer
Optional components
Image transformation sidecar
Some institutions require support for WMF/EMF files or PDF post-processing. Run the sidecar next to the main container and reference it via TRANSFORM_IMAGE_URL
:
docker run \
--rm \
-d \
-p 127.0.0.1:3001:3001 \
--name os-aps-transform \
registry.gitlab.com/sciflow/development/file-transform-sidecar:latest
Set TRANSFORM_IMAGE_URL=http://os-aps-transform:3001
(or http://localhost:3001
if you keep it on the host network).
Windows administration
When running ad-hoc docker run
commands from PowerShell, break lines with backticks (```). The Compose setup above is cross-platform and avoids quoting issues.
Development mode
If you plan to modify exporter code or contribute upstream, see the Development Setup Guide for instructions on building the stack locally.
Setup on various environments
Reverse proxy example (Apache)
Serve the application through a reverse proxy that terminates TLS and forwards traffic to port 3000 on the Docker host. The snippets below target Apache 2.4.58 running on the same machine as the containers.
Enable the required modules once:
sudo a2enmod proxy proxy_http headers ssl
sudo systemctl reload apache2
Port 80 virtual host (/etc/apache2/sites-available/000-default.conf
)
<VirtualHost *:80>
ServerName aps.university.edu
ServerAdmin webmaster@university.edu
ProxyRequests Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
ProxyPass / http://127.0.0.1:3000/ nocanon
ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog ${APACHE_LOG_DIR}/osaps-error.log
CustomLog ${APACHE_LOG_DIR}/osaps-access.log combined
</VirtualHost>
TLS virtual host (/etc/apache2/sites-available/default-ssl.conf
)
<VirtualHost *:443>
ServerName aps.university.edu
ServerAdmin webmaster@university.edu
SSLEngine on
SSLCertificateFile /etc/ssl/certs/aps.university.edu.crt
SSLCertificateKeyFile /etc/ssl/private/aps.university.edu.key
ProxyRequests Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
ProxyPass / http://127.0.0.1:3000/ nocanon
ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog ${APACHE_LOG_DIR}/osaps-error.log
CustomLog ${APACHE_LOG_DIR}/osaps-access.log combined
</VirtualHost>
Reload Apache after enabling the sites:
sudo a2ensite 000-default.conf default-ssl.conf
sudo systemctl reload apache2
The critical directive is AllowEncodedSlashes NoDecode
, which prevents the proxy from rewriting %2F
sequences that OS-APS uses in download URLs.
Troubleshooting
Container exits with code 139 during exports
Large images expand dramatically in memory when they are rasterized. If the container exits with code 139, raise the memory limit for the Docker service or move the export job to a host with more RAM. When possible, ask authors to upload images that are already optimized (PNG for graphics, JPEG for photos).
Encoded slashes cause 404 responses behind a proxy
Some proxies decode %2F
to /
before forwarding the request, breaking download links. Ensure your reverse proxy forwards encoded slashes untouched. For Apache use AllowEncodedSlashes NoDecode
; for NGINX set proxy_set_header X-Original-URI $request_uri;
and disable rewriting of encoded characters.
Logs and support
Use docker compose logs osaps
(or docker logs <container>
) to inspect runtime issues. When asking for help, include the container image version, relevant environment variables, and the reverse proxy configuration you are using.
Next steps
- Configure SMTP and authentication to match your university policies.
- Add monitoring (Prometheus, ELK) and alerting before inviting authors.
- Plan regular updates: pull the latest image, re-run
docker compose up -d
, and verify exports using your staging environment. - Provide a SENTRY_DSN environment variable to enable error reporting to a Sentry / Gitlab instance.
- Provide a PrinceXML license file using PRINCE_LICENSE_PATH