Skip to content

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.

  • 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 the osaps-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.

  1. 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 example git@git.university.edu:press/os-aps-templates.git.
  2. 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
3. Keep the upstream remote so you can pull fixes:

git remote rename origin upstream
4. Whenever templates change upstream, synchronize them into your campus repository and push:

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.

  1. Collect the font files (OTF or TTF) that you have the right to distribute.
  2. Store them in a dedicated directory or Docker volume so they can be mounted read-only into the container.
  3. 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.

  1. Create a bucket dedicated to OS-APS (for example os-aps-manuscripts).
  2. Enable versioning on the bucket. With AWS you can run:

aws s3api put-bucket-versioning \
  --bucket os-aps-manuscripts \
  --versioning-configuration Status=Enabled
3. Configure lifecycle rules that transition stale object versions to a cheaper storage class and permanently expire deleted versions after your retention period. Example:

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
4. Create an access key pair with permissions limited to that bucket (read, write, list, delete, and the ability to perform multipart uploads).

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

  1. Start the stack:
docker compose up -d
  1. Follow the logs during the first startup:
docker compose logs -f
  1. When the app reports Server started on port 3000, access http://localhost:3000 (or your reverse proxy URL) and create the first administrator account.
  2. Upload a template-managed manuscript and confirm that exports pick up your custom templates and fonts.
  3. 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