Linkr
Home Resources Tools Documentation Blog Demo
FR
  • What is Linkr?
  • Deployment modes
  • Quick start
  • Local install
  • With Docker
  • Manual install
  • Client-only
  • Your first project
  • Workspaces and projects
  • The data pipeline
  • Entities and sharing
  • Versioning and collaboration
  • Overview
  • Projects
  • Wiki
  • Plugins
  • Members and roles
  • Settings
  • Schemas
  • Databases
  • Derived sub-databases
  • Data quality
  • Data catalog
  • SQL script collections
  • ETL pipelines
  • Overview
  • Mapping projects
  • Global view
  • Target concepts
  • Mapping editor
  • Suggestions
  • Evaluation
  • Export
  • Overview
  • Concepts
  • Cohorts
  • Patient data
  • Pipeline
  • Datasets
  • IDE
  • Web apps
  • Versioning
  • Overview
  • Tabs and widgets
  • Built-in widgets
  • Analysis widgets
  • Control charts (SPC)
  • Surveys and eCRF
  • R and Python code
  • Filters, settings and export
  • Overview
  • Presentation mode
  • Exporting a report
  • Agents
  • Model providers
  • Skills
  • Authoring through MCP
  • Import and export
  • Git versioning
  • Community catalog
  • Publishing content
  • Production install
  • Configuration
  • Authentication and permissions
  • Files on the server
  • Backup and restore
  • Glossary
  • Keyboard shortcuts
  • Release notes
Documentation Administration Production install

Production install

Deploying a server instance with Docker: the file to download, the secret key, what to change for a real hostname, and how to upgrade.

In short

A server instance deploys from one Docker Compose file and a secret key you generate. Two services are enough — the application and the web front —, the database creates itself, and migrations apply on every start. For a real hostname two settings need changing: the allowed origin and the TLS certificate, which Linkr does not provide.

Client Not available in client-only mode — this feature requires a backend. Backend Available with the FastAPI backend.

Two ways to deploy

Server mode

Docker, on a machine at your institution.

User accounts, shared storage, server-side code execution, git versioning. This page is about that.

Static site

Files dropped on any static host.

Everything runs in the browser. No accounts, no shared storage, no git versioning — see Deployment modes.

Starting an instance

One file is all it takes. It is self-contained: no clone, no build.

curl -O https://framagit.org/interhop/linkr/linkr/-/raw/main/docker/docker-compose.hub.yml
export LINKR_SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(48))")
docker compose -f docker-compose.hub.yml up

Then open http://localhost:3000: the setup wizard takes it from there.

The secret key: generated once, kept forever

It signs login tokens and encrypts the passwords of registered databases. Without it the server refuses to start — deliberately. Losing it makes those secrets unreadable: back it up as carefully as your data.

What exactly it protects and what rotating it implies: Configuration.

What the file starts

Two services, and nothing else to install.

ServiceRolePort
webThe interface, served by nginx, which also relays calls to the application.3000
apiThe application: data, code execution, git.8000

The browser only ever talks to port 3000: calls go through /api/ and are relayed internally. Port 8000 therefore does not need exposing, and you can remove its publication from the file.

No database service

By default the data fits in a SQLite file stored with everything else. There is no PostgreSQL container to run and no database password to choose. For sustained multi-user use PostgreSQL remains possible by changing the database address — see Configuration.

The setup wizard

On first start the application notices that no account exists and shows a three-step wizard.

1

Database

Shows, read-only, the engine and location actually in use. The database is configured server-side and created automatically; to change it, edit the configuration and restart.

2

Administrator account

Username and password for the first administrator. This step is only possible while no account exists.

3

Default data

Offers to install a demo workspace — an OMOP database, mappings, an ETL pipeline, example projects. Needs network access to the catalog; with no network the instance starts empty and the wizard still finishes.

No requirement is enforced on the administrator password

The application only checks that both entries match. The strength of that password — the most privileged account on the instance — is entirely up to you.

Moving to a real hostname

The shipped file is set up for localhost. Two things need handling before exposing the instance.

The allowed origin

The application only accepts calls from declared origins. While LINKR_CORS_ORIGINS is http://localhost:3000, an instance served on any other name will have all its calls blocked by the browser. Declare the real public origin:

- LINKR_CORS_ORIGINS=https://linkr.example.org

A wildcard is refused at startup

Setting * makes the launch fail, with an explicit message. This is not an annoyance to work around: since calls carry session credentials, a wildcard would let any website query your instance on behalf of your users.

TLS encryption

Linkr does not terminate HTTPS. The web container listens in the clear on port 80; putting a TLS terminator in front of it — nginx, Traefik, HAProxy, or your institution’s reverse proxy — and managing the certificates there is your job.

If you front it with your own proxy, two details matter

WebSockets must be relayed on /api/ too, not only on /ws/: the execution terminal opens its connection under /api/. A proxy that upgrades only /ws/ yields a terminal that never connects.

Timeouts must be long. An R or Python run and a large query go well past the 60-second default; the shipped proxy waits up to an hour.

Maximum upload size: two ceilings, the lower one wins

The shipped proxy accepts request bodies up to 512 MB, while the application allows 2 GB. So 512 MB is what applies. To take larger files, raise the proxy’s limit — or better, avoid the upload: put the file on the server and point at it by path, see Files on the server.

Where the data lives

Everything your users create — the database and every file — sits in one folder, mounted into the container. The images hold no data of their own.

By default it is a named Docker volume: it survives restarts and upgrades, but Docker owns it and it is awkward to copy. To keep it in a real folder, replace the volume line:

volumes:
  - /srv/linkr:/root/.linkr

A mounted folder is never deleted by accident

docker compose down -v destroys a named volume; a mounted folder is never touched. That is the second reason to prefer one for anything you care about.

What that folder contains in detail is in Configuration, and what actually needs copying in Backup and restore.

Upgrading

Versions are pinned on purpose: a latest would let an update move the application under a running instance without anyone asking for it.

To upgrade, change both image lines to the new version, then restart:

docker compose -f docker-compose.hub.yml pull
docker compose -f docker-compose.hub.yml up -d

Both lines change together

The two images stamp the same format version into exports: a mismatched pair writes exports that disagree about their own format.

Back up first, because rolling back is not symmetrical

Schema migrations apply automatically on start. Going back to the previous image does not undo them: an upgraded instance does not come back down by a mere version change. The backup taken before the upgrade is your only real rollback.

Migrations are never run by hand

They apply on every start and do nothing when the schema is already current. No command is to be run during an upgrade.

Going further

  • Configuration — every variable, and what it changes.
  • Backup and restore — what to copy, and in which order to restore.
  • Authentication and permissions — creating accounts after the wizard.
  • Deployment modes — what the choice of mode changes.
PreviousPublishing contentNextConfiguration

Product

  • Home
  • Demo

Resources

  • Documentation
  • Resources
  • Tools
  • Blog

Community

  • Framagit source code
  • Github source code

About

  • InterHop.org
  • Contact

2021–2026 InterHop — CC BY-NC-SA 4.0 (site) · GPLv3 (software)