Installation

Reverse Proxy

FediSuite runs internally on port 3000 and without a reverse proxy is only reachable directly via this port — without HTTPS, without a domain. Traefik takes over this role: it accepts requests on ports 80 and 443, automatically issues TLS certificates via Let's Encrypt, and forwards traffic to FediSuite.

What is a Reverse Proxy?

A reverse proxy sits between the internet and your application. When someone visits https://your-domain.com, the reverse proxy receives the request, handles HTTPS encryption, and forwards it internally to FediSuite — on port 3000, unencrypted, only within the Docker network.

Traefik is a reverse proxy built specifically for Docker environments. It automatically detects which containers are running, reads their configuration from so-called labels, and sets up routing and TLS certificates on its own — without you having to maintain configuration files manually.

How the data flow works

Browser

https://your-domain.com

Port 443 (HTTPS)

Traefik

TLS termination

Port 3000 (internal)

FediSuite app

Docker network

Important: remove ports: 3000

As soon as you use Traefik as a reverse proxy, port 3000 must not be published directly on the host anymore. The port mapping 3000:3000 in the app service makes the port reachable directly on the server — and therefore without HTTPS and without a domain name. Traefik communicates with FediSuite internally through the Docker network, without the port needing to be exposed.

Without Traefik (with port mapping)

  app:
    ...
    ports:
      - "3000:3000"  # remove!
    ...

With Traefik (no port mapping)

  app:
    ...
    # ports: completely removed
    labels:
      - "traefik.enable=true"
    ...
Note: Port 3000 remains active internally — Traefik knows it via the label loadbalancer.server.port=3000. You don't need to configure it; you're only removing the public mapping.

Scenario 1: External Traefik

This is typical if you're already running other services with Traefik on the same server. Traefik runs in its own stack, and FediSuite joins the existing external Docker network — usually called proxy.

1

Check prerequisites

Your external Traefik must meet these conditions:

The Docker provider is enabled (--providers.docker=true).
There is a cert resolver for Let's Encrypt. Remember its name — you need it in the tls.certresolver label. In the example it's called letsEncrypt.
An external Docker network exists through which Traefik reaches containers. In the example it's called proxy.
2

Create the external network (if it doesn't exist yet)

The proxy network must be created once on the server if it doesn't already exist:

bash
docker network create proxy
3

Edit docker-compose.yml

Open the docker-compose.yml and make the following three changes:

① Remove ports: from the app service and uncomment labels + networks:

docker-compose.yml — app service
  app:
    image: ${FEDISUITE_IMAGE:-christinloehner/fedisuite:latest}
    pull_policy: always
    env_file:
      - .env
    environment:
      - ENABLE_SCHEDULER=false
      - ENABLE_POSTS_REFRESH=false
      - ENABLE_IDLE_REMINDER=false
      - ENABLE_TIPS_ENGINE=false
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./uploads:/app/uploads
      - ./plugins:/app/plugins
    # ports: removed — Traefik takes over
    restart: unless-stopped
    command: sh -c "node server/init-db.js && node server/index.js"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.fedisuite.rule=Host(`your-domain.com`)"
      - "traefik.http.services.fedisuite.loadbalancer.server.port=3000"
      - "traefik.http.routers.fedisuite.service=fedisuite"
      - "traefik.http.routers.fedisuite.tls.certresolver=letsEncrypt"
      - "traefik.docker.network=proxy"
    networks:
      - default
      - proxy

② Uncomment the networks: stanza at the end of the file:

docker-compose.yml — end of file
networks:
  proxy:
    external: true

external: true tells Docker Compose that this network already exists and should not be created anew.

4

Restart the stack

bash
docker compose up -d

Traefik automatically detects the new container, reads the labels, and issues a Let's Encrypt certificate for your domain within seconds.

Scenario 2: Traefik in docker-compose.yml

If FediSuite is the only service on your server, the simplest approach is to include Traefik directly in FediSuite's docker-compose.yml. Traefik then runs as a fifth container in the same stack — no external network, no separate setup.

1

Add the Traefik service

Add the following traefik service at the top of the docker-compose.yml. Replace your@email.com with your actual email address — Let's Encrypt needs it for certificate notifications.

docker-compose.yml — traefik service
services:

  traefik:
    image: traefik:v3
    restart: unless-stopped
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--certificatesresolvers.letsEncrypt.acme.tlschallenge=true"
      - "--certificatesresolvers.letsEncrypt.acme.email=your@email.com"
      - "--certificatesresolvers.letsEncrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    networks:
      - proxy

  db:
    # ... unchanged ...

  app:
    # ... see step 2 ...
2

Edit the app service

Remove ports:, add labels and the proxy network:

docker-compose.yml — app service
  app:
    image: ${FEDISUITE_IMAGE:-christinloehner/fedisuite:latest}
    pull_policy: always
    env_file:
      - .env
    environment:
      - ENABLE_SCHEDULER=false
      - ENABLE_POSTS_REFRESH=false
      - ENABLE_IDLE_REMINDER=false
      - ENABLE_TIPS_ENGINE=false
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./uploads:/app/uploads
      - ./plugins:/app/plugins
    # ports: removed — Traefik takes over
    restart: unless-stopped
    command: sh -c "node server/init-db.js && node server/index.js"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.fedisuite.rule=Host(`your-domain.com`)"
      - "traefik.http.services.fedisuite.loadbalancer.server.port=3000"
      - "traefik.http.routers.fedisuite.service=fedisuite"
      - "traefik.http.routers.fedisuite.tls.certresolver=letsEncrypt"
      - "traefik.docker.network=proxy"
    networks:
      - default
      - proxy
3

Define the network at the end of the file

Since Traefik and FediSuite run in the same stack, the network is not external — Docker Compose creates it itself:

docker-compose.yml — end of file
networks:
  proxy:

No external: true — this network belongs to this stack.

4

Start the stack

bash
docker compose up -d

Traefik starts, detects the app container via the Docker provider, and automatically issues a TLS certificate for your domain. The certificate is persistently stored under ./letsencrypt/acme.json and automatically renewed when it expires.

Traefik Labels explained

Via labels in the docker-compose.yml, FediSuite tells Traefik how it should be routed. Each label has a clearly defined meaning:

traefik.enable=true

Enables Traefik for this container. Since exposedbydefault=false is set (Scenario 2) or is generally recommended, every container that Traefik should manage must explicitly carry this label.

traefik.http.routers.fedisuite.rule=Host(`your-domain.com`)

Defines which domain Traefik routes requests to this container for. Replace your-domain.com with your actual domain. The name fedisuite in the label is a freely chosen internal identifier for this router — it just needs to be unique.

traefik.http.services.fedisuite.loadbalancer.server.port=3000

Specifies the port on which the container listens internally. FediSuite uses port 3000. Traefik forwards requests internally to this port — without requiring the port to be exposed.

traefik.http.routers.fedisuite.service=fedisuite

Links the router to the service defined above. With a single container this is usually implicit, but specifying it explicitly never hurts and prevents ambiguity.

traefik.http.routers.fedisuite.tls.certresolver=letsEncrypt

Enables TLS for this router and specifies which cert resolver should issue the certificate. The name letsEncrypt must exactly match the name you gave the ACME resolver in your Traefik configuration.

traefik.docker.network=proxy

Tells Traefik which Docker network to use to reach the container. Since the app container is in two networks (default and proxy), Traefik needs to know which one to use — otherwise it might choose the wrong one.

Troubleshooting

No certificate / browser shows certificate error

  • The DNS A record for the domain doesn't point to the server IP yet — wait for propagation.
  • Port 80 is blocked by the firewall — Let's Encrypt needs port 80 for the TLS challenge.
  • The cert resolver name in the label doesn't match the name configured in Traefik.
  • Let's Encrypt rate limit reached — wait a few hours and try again.

Traefik can't find the container / 404

  • traefik.enable=true is missing from the app service.
  • The label traefik.docker.network=proxy is missing or names the wrong network.
  • The app container is not in the proxy network — networks: is missing from the service.
  • docker compose up -d was not run after the change.

FediSuite responds but over HTTP instead of HTTPS

  • The HTTP-to-HTTPS redirect is not configured in Traefik. In Scenario 2, the redirections lines in the Traefik command are required.
  • The tls.certresolver label is missing — without it, Traefik doesn't set up TLS.

Port 3000 reachable from outside even though Traefik is used

  • The ports: - "3000:3000" line was not removed from docker-compose.yml. Remove it and run docker compose up -d.
Check Traefik logs
# Scenario 1: Traefik in its own stack
docker logs traefik -f

# Scenario 2: Traefik in the FediSuite stack
docker compose logs traefik -f