Portainer Templates logo

Portainer Templates

tela tela

Stack

ProductivityDocumentation

Self-hostable, markdown-native team wiki: Go + PostgreSQL backend, a React editor with live Yjs collaboration, full-text + optional semantic search, WebDAV sync, public/blog spaces, Slidev decks and PDF export. A built-in MCP server makes AI agents first-class editors, and Atlas can generate a cited wiki from your existing sources (git, Jira). After the stack is up, open the app on :8780 and complete /setup to create your admin account. GitHub: zcag/tela

Source details

Repo: zcag/tela
Stars: 47
Forks: 4
Language: Go
License: AGPL-3.0
Updated: 5 days ago
Website: telawiki.com/

Configuration

Type
Compose
Platform
linux
Env vars
TELA_PUBLIC_BASE_URL=http://localhost:8780TELA_PG_PASSWORD=TELA_SHARE_SECRET=TELA_API_KEY_SECRET=
Restart
unless-stopped
Source

Source

Notes

Three secrets are required and have no defaults: TELA_PG_PASSWORD, TELA_SHARE_SECRET and TELA_API_KEY_SECRET (generate each with openssl rand -hex 32). Keep them stable across redeploys — rotating TELA_API_KEY_SECRET invalidates every personal access token, and TELA_SHARE_SECRET invalidates outstanding share links. The app is served on port 8780; open it and complete /setup to create the first admin.

Services

proxy

Configuration

Image
ghcr.io/zcag/tela-proxy:0.7.0
Ports
8780:80
Volumes
/data : tela-caddy-data/config : tela-caddy-config
Env vars
TELA_SITE_ADDRESS=:80TELA_UPSTREAM_BACKEND=backend:8080TELA_UPSTREAM_FRONTEND=frontend:80
Restart
unless-stopped

Image details

User: zcag

backend

Configuration

Image
ghcr.io/zcag/tela-backend:0.7.0
Env vars
TELA_PUBLIC_BASE_URL=${TELA_PUBLIC_BASE_URL:-http://localhost:8780}TELA_SHARE_SECRET=${TELA_SHARE_SECRET}TELA_API_KEY_SECRET=${TELA_API_KEY_SECRET}TELA_DATABASE_URL=postgres://tela:${TELA_PG_PASSWORD}@postgres:5432/tela?sslmode=disableTELA_GOTENBERG_URL=http://gotenberg:3000TELA_PDF_RENDER_BASE_URL=http://proxyTELA_DECK_URL=http://deck:3344
Restart
unless-stopped

Image details

User: zcag

postgres

Configuration

Image
pgvector/pgvector:pg17
Volumes
/var/lib/postgresql/data : tela-pgdata
Env vars
POSTGRES_USER=telaPOSTGRES_PASSWORD=${TELA_PG_PASSWORD}POSTGRES_DB=tela
Restart
unless-stopped

Image details

Pulls: 148.5M
User: pgvector
Created: Jan 29, 2024
Updated: 2 days ago
Status: active

frontend

Configuration

Image
ghcr.io/zcag/tela-frontend:0.7.0
Restart
unless-stopped

Image details

User: zcag

deck

Configuration

Image
ghcr.io/zcag/tela-deck:0.7.0
Volumes
/data : tela-deckcache
Restart
unless-stopped

Image details

User: zcag

gotenberg

Configuration

Image
gotenberg/gotenberg:8
Restart
unless-stopped

Image details

Pulls: 82.4M
User: gulnap
Created: Jun 18, 2021
Updated: 1 day ago
Status: active

Standalone Install

Select an install method, to see config/commands for deploying tela

Installation method

Install on Portainer

Import all app templates into your Portainer instance, for easy 1-click deploys

  1. Ensure both Docker and Portainer are installed, and up-to-date
  2. Log into your Portainer web UI
  3. Under Settings → App Templates, paste the below URL
  4. Head to Home → App Templates, and the list of apps will show up
  5. Select tela, fill in any config options, and hit Deploy

Template Import URL

https://raw.githubusercontent.com/Lissy93/portainer-templates/main/templates.json
Show Me demo
Original stackfile

The compose file this template deploys, straight from its repo:

version: "3.8"

# tela — self-hostable markdown-native team wiki (https://telawiki.com)
# Caddy `proxy` is the only web-exposed service and is the mandatory single
# entrypoint; it fronts the Go `backend` and the static `frontend`. Postgres
# uses the pgvector image (semantic search needs the `vector` extension).
# The three required secrets have NO defaults — set them in Portainer before
# deploying and keep them stable (rotating TELA_API_KEY_SECRET invalidates all
# personal access tokens). After the stack is up, open :8780 and complete /setup
# to create the admin account.

services:

  proxy:
    image: ghcr.io/zcag/tela-proxy:0.7.0
    restart: unless-stopped
    environment:
      TELA_SITE_ADDRESS: ":80"
      TELA_UPSTREAM_BACKEND: backend:8080
      TELA_UPSTREAM_FRONTEND: frontend:80
    ports:
      - "8780:80"
    volumes:
      - tela-caddy-data:/data
      - tela-caddy-config:/config
    depends_on:
      - backend
      - frontend

  backend:
    image: ghcr.io/zcag/tela-backend:0.7.0
    restart: unless-stopped
    environment:
      TELA_PUBLIC_BASE_URL: ${TELA_PUBLIC_BASE_URL:-http://localhost:8780}
      TELA_SHARE_SECRET: ${TELA_SHARE_SECRET}
      TELA_API_KEY_SECRET: ${TELA_API_KEY_SECRET}
      TELA_DATABASE_URL: postgres://tela:${TELA_PG_PASSWORD}@postgres:5432/tela?sslmode=disable
      TELA_GOTENBERG_URL: http://gotenberg:3000
      TELA_PDF_RENDER_BASE_URL: http://proxy
      TELA_DECK_URL: http://deck:3344
    expose:
      - "8080"
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: pgvector/pgvector:pg17
    restart: unless-stopped
    environment:
      POSTGRES_USER: tela
      POSTGRES_PASSWORD: ${TELA_PG_PASSWORD}
      POSTGRES_DB: tela
    volumes:
      - tela-pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U tela -d tela"]
      interval: 5s
      timeout: 3s
      retries: 20
      start_period: 10s

  frontend:
    image: ghcr.io/zcag/tela-frontend:0.7.0
    restart: unless-stopped
    expose:
      - "80"

  deck:
    image: ghcr.io/zcag/tela-deck:0.7.0
    restart: unless-stopped
    volumes:
      - tela-deckcache:/data
    expose:
      - "3344"

  gotenberg:
    image: gotenberg/gotenberg:8
    restart: unless-stopped
    expose:
      - "3000"

volumes:
  tela-pgdata:
  tela-deckcache:
  tela-caddy-data:
  tela-caddy-config:

Or deploy it directly from the source:

git clone https://github.com/lissy93/portainer-templates
cd portainer-templates
docker compose -f sources/stacks/tela.yml up -d

More install options in our documentation, or see zcag/tela for app-specific guidance.

Container Documentation

postgres Documentation

Open-source vector similarity search for Postgres

gotenberg Documentation

A Docker-based API for converting documents to PDF

Serve tela on your own domain behind Caddy, Nginx or Traefik. Fill in your domain and copy the result. It's a starting point, some apps need their own base URL or extra headers set too.

Proxying tela.example.com to http://proxy:80

Add this to your Caddyfile

tela.example.com {
	reverse_proxy http://proxy:80
}

Check the logs first

Nine times out of ten the logs tell you exactly what went wrong.

  • In Portainer, go to Containers, click the container, then Logs. Or run docker logs <container>
  • Exit codes help too: 137 means killed, usually out of memory. 126 or 127 means the command inside the image is broken.

Port already in use

If deployment fails with "Bind for 0.0.0.0:8780 failed: port is already allocated", something else on your server is using that port.

  • Find what's using it: sudo ss -tlnp | grep :8780
  • Stop the other service, or pick a different host port. In 8780:80 only the left number is yours to change, the right one belongs to the app.

Running but the page won't load

The container is up but nothing appears in your browser.

  • Use your server's real IP: http://your-server-ip:8780. The 0.0.0.0 link Portainer shows isn't a real address.
  • Give it a minute after first deploy, tela can take a while to initialise.
  • Make sure your firewall allows the port, e.g. sudo ufw allow 8780

Image won't pull

Test the pull directly on the host: docker pull ghcr.io/zcag/tela-proxy:0.7.0

  • "manifest unknown" means the tag no longer exists.
  • "toomanyrequests" is the Docker Hub rate limit. Log in with docker login to raise it.
  • "no space left on device" means a full disk. Reclaim space with docker system prune

"exec format error"

This means the image was built for a different CPU architecture than your server.

  • Check yours with uname -m: x86_64 is amd64, aarch64 is arm64. Raspberry Pi and other ARM boards are the usual culprits.

Container keeps restarting

The unless-stopped restart policy relaunches the app after every crash, so the real error can scroll past.

  • Check the logs right after a restart, the last few lines before it died are the useful ones.
  • Get the exit code with docker inspect <container> --format '{{.State.ExitCode}}'
  • Still stuck? Redeploy once with the restart policy set to no so the failure stays visible.

Stack won't deploy

Compose stacks fail fast on small mistakes, and Portainer shows the reason just above the editor.

  • YAML only accepts spaces for indentation, a single tab breaks the whole file.

Raise an issue

Found something which isn't working as it should? Here's how to report it.

A Compose stack

tela is a Compose stack, a set of containers (6 of them) defined in one file and brought up together by Portainer, then started and stopped as a single app.

The services

This stack is built from 6 containers that run side by side. Here's each one, with the image it runs and anything it waits for first:

  • proxy runs ghcr.io/zcag/tela-proxy:0.7.0, starts after backend, frontend
  • backend runs ghcr.io/zcag/tela-backend:0.7.0, starts after postgres
  • postgres runs pgvector/pgvector:pg17
  • frontend runs ghcr.io/zcag/tela-frontend:0.7.0
  • deck runs ghcr.io/zcag/tela-deck:0.7.0
  • gotenberg runs gotenberg/gotenberg:8

Ports

A port is the door the app answers on. A mapping like 8780:80 means it's reachable on port 8780 of your server, where the left number is yours to change and the right one belongs to the app. Once it's running, open http://your-server-ip:8780 in a browser. It opens:

  • 8780:80, likely the web interface

Volumes

A volume is where tela keeps its files so they survive an update or a restart. Without one, anything it saves would sit inside the container and vanish the moment it's recreated. This template mounts:

  • /data kept in the tela-caddy-data volume Docker manages
  • /config kept in the tela-caddy-config volume Docker manages
  • /var/lib/postgresql/data kept in the tela-pgdata volume Docker manages
  • /data kept in the tela-deckcache volume Docker manages

Environment variables

Environment variables are the settings you hand over when you deploy, things like a password or a timezone. tela takes 13 of them, all with defaults you can leave alone or tweak:

  • TELA_SITE_ADDRESS, defaults to :80
  • TELA_UPSTREAM_BACKEND, defaults to backend:8080
  • TELA_UPSTREAM_FRONTEND, defaults to frontend:80
  • TELA_PUBLIC_BASE_URL, defaults to http://localhost:8780
  • TELA_SHARE_SECRET, pulled from your own environment
  • TELA_API_KEY_SECRET, pulled from your own environment
  • TELA_DATABASE_URL, defaults to postgres://tela:TELA_PG_PASSWORD@postgres:5432/tela?sslmode=disable
  • TELA_GOTENBERG_URL, defaults to http://gotenberg:3000
  • TELA_PDF_RENDER_BASE_URL, defaults to http://proxy
  • TELA_DECK_URL, defaults to http://deck:3344
  • POSTGRES_USER, defaults to tela
  • POSTGRES_PASSWORD, pulled from your own environment
  • POSTGRES_DB, defaults to tela

Restart policy

The restart policy here is unless-stopped, so Docker restarts tela after a crash or reboot, but leaves it off when you stop it on purpose. You can change this on the deploy screen. The choices are no (never restart), on-failure (only after a crash), unless-stopped (restart unless you stop it), and always (bring it back no matter what).

Networking

Portainer puts these services on one shared private network, so they can find each other by name (like proxy) while only the ports above are open to you.

Platform

The platform is linux, the kind of system the container is built to run on. Docker and Portainer handle this on a normal Linux server.

Open source license

tela is open source, released under the AGPL-3.0 license. In plain terms the code is out in the open, so you're free to run it and change it to fit what you need.

Portainer app templates

Zooming out, this whole page comes from a Portainer app template: a short recipe telling Portainer how to set tela up. Add the template list to Portainer once, then deploying tela is a click rather than a wall of config.