---
title: "Setup"
manual: "Kitodo.Presentation"
version: "dev-demo"
source: "Demo/Setup.rst"
rendered: "2026-09-27T16:21:24+00:00"
---

# Setup {#demo-setup}

The demo is built by the script `Build/Demo/setup-demo.sh` in the
`demo` branch. It creates a **self-contained, runnable TYPO3 13.4 +
SQLite** site in a directory of your choice. The `dlf` extension is
symlinked into the site from the current checkout, so the site always runs the
exact code of the branch you are on.

No Docker, no Apache Solr and no theme CSS are required. Instead of pointing
the viewer at a public document, the script installs a small **local sample
document** (a METS file plus three placeholder pages, thumbnails, ALTO
fulltext and per-page PDFs) and serves it on its own static HTTP port, so the
PageView viewer works end to end completely offline.

## Requirements {#requirements}

-   PHP 8.2 or newer (a Homebrew PHP is fine) with the extensions used by
    TYPO3. PHP 8.5 works as well.
-   Composer.
-   A checkout of this repository on the `demo` branch.

The script pins the Composer PHP platform to 8.4.99 for you, so the dependency
resolution does not depend on the installed PHP version.

## Running the script {#running-the-script}

```bash
Build/Demo/setup-demo.sh
```

This creates the site in `$HOME/kitodo-demo-site` and prints the URLs to
open. Run it again at any time to re-sync an existing site with the current
checkout (the script is idempotent).

## Options {#options}

| Option | Default | Description |
| --- | --- | --- |
| `--dir <path>` | `$HOME/kitodo-demo-site` | Where to create the site. |
| `--port <n>` | 8090 (next free port if taken) | Frontend dev-server port / base URL. |
| `--base-url <url>` | (localhost dev server) | Serve the site under a public base URL instead of the localhost dev server (e.g. behind an Apache vhost or reverse proxy). It becomes the TYPO3 site base, and the web server must serve `<dir>/public` at that URL. Not allowed together with `--serve`. |
| `--data-url <url>` | (localhost data server) | Public base URL of the sample data files (`<dir>/kitodo-demo`). Required with `--base-url` unless `--no-sample` is given. |
| `--branch <name>` | current git branch | `dlf` branch to install. |
| `--user <name>` | `admin` | Backend admin username. |
| `--password <pw>` | see below | Backend admin password. For localhost installs (no `--base-url`) the default `demo-Passw0rd!` is used when not given. For web installations (`--base-url`) a random password is generated and printed at the end when none is given (it is stored in `<dir>/.admin-password` and reused on re-runs). |
| `--style <name>` | `aurora` | Viewer theme to use. The available themes are the subdirectories of `Build/Demo/styles/`. See [Themes](Themes.html#demo-themes). |
| `--serve` | (off) | Start both servers in the foreground after setup. |
| `--no-sample` | (off) | Skip the local sample document. The on-page form then starts empty and you paste any METS / IIIF URL. |
| `-h`, `--help` |  | Show this help. |

## Workarounds baked into the setup {#workarounds-baked-into-the-setup}

The script applies several workarounds that a fresh install otherwise needs:

-   `enableContentLengthHeader = 0` in the site TypoScript, so the
    PageView proxy (a non-seekable stream) is not given a bogus
    `Content-Length: 0` header by the cms-frontend content-length
    middleware.
-   `plugin.tx_dlf_metadata.settings.separator` set, because that
    setting has no default and the metadata controller crashes on multivalued
    metadata when it is null.
-   The FE `cacheHash.requireCacheHashPresenceParameters['tx_dlf[id]']`
    and `pageNotFoundOnCHashError = 0` so a viewer request carrying
    `tx_dlf[id]` renders uncached instead of 404ing on the missing cHash.
-   The viewer map container height is provided by the extension itself, so no
    theme CSS is needed for the viewer to render.

## A separate data server {#a-separate-data-server}

The sample data (METS, page images, thumbnails, media) is served on its own
static port, distinct from the frontend app. This is deliberate: the built-in
PHP server is single-threaded, and a request that reaches back into the same
port (the app fetching the METS and page images server-side) would deadlock it.
Keeping the data on a different port avoids that.
