docs(operator): document app support for self-hosted instances (#3429)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-12 19:58:56 +02:00
1 parent 13960a0bb3
commit 9bc43c0c08
44 files changed
+281 -472

No files matched your search

@@ -19,7 +19,7 @@ Every path names a channel, either `stable` or `canary`. The two are published i
| `/arch/` | A pacman repository, one directory per architecture |
| `/deb/` | An apt repository in the `dists` and `pool` layout |
| `/rpm/` | A dnf repository, one directory per channel and architecture |
| `/keys/` | The public signing key for the apt and rpm repositories |
| `/keys/` | The public signing key for every repository |
## What it guarantees
@@ -29,6 +29,4 @@ Artifacts under a version directory never change once published, so they are cac
## Signing
The apt and rpm repositories are signed. The public key lives at `/keys/fluxer-archive-keyring.asc`, and the entrypoint files reference it, so a client verifies every package it installs.
The flatpak and pacman repositories are unsigned and rely on HTTPS for transport integrity. pacman still verifies each package against the SHA256 its index records, and flatpak verifies each object against its content address.
Every repository is signed with one key. `/keys/` publishes it as `fluxer-archive-keyring.asc`, and as `fluxer-archive-keyring.gpg` for apt. [Linux repositories](/downloads/linux-repositories/) shows how each repository gets the key.
@@ -105,7 +105,7 @@ The policy applies to a response the Media Proxy generates, and a shared cache i
A `static` or `relay` endpoint ignores the policy. The [upload relay](/media-proxy/upload-relay/) and the [operator and internal endpoints](/media-proxy/routes/#operator-and-internal-endpoints) are exempt from it. A method other than `GET` or `HEAD` on a read path returns 405 whatever its `Origin`.
The reference self-hosted deployment leaves the policy `off`. An operator who turns it on gets the instance public origin as the only entry, and [Media Proxy settings](/operator/configuration/#media-proxy-settings) states how to allow `https://web.fluxer.app` as well.
The reference self-hosted deployment leaves the policy `off`. An operator who turns it on gets the instance public origin as the only entry.
## Signed attachment URLs
File diff suppressed because it is too large. Load diff
@@ -6,8 +6,18 @@ description: Bring up a Fluxer instance with Docker Compose, from a fresh host t
import InstallerChecksum from '@/components/InstallerChecksum.astro';
:::tip[Plutonium and donations fund Fluxer]
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer). The Operator Pass is coming, and adds a direct line to the team for help and feedback.
:::tip[The Operator Pass is coming]
The [Operator Pass](https://fluxer.app/pass) gives you a direct line to the Fluxer team. It goes on sale in early November 2026 for $199 or €199, paid once. The price goes up on 1 January 2027. Pass holders get these perks for life.
- A private channel in Fluxer Labs where the team answers questions about your instance
- The Operator role in Fluxer Labs
- An Operator Pass profile badge
- Invitations to test new features on your instance
- Your avatar and name on the Fluxer website, if you want
The pass unlocks nothing in the software, and self-hosting stays free. If you have Visionary, you already have the pass.
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer).
:::
By the end you have a Fluxer instance on a hostname you own, running the web app, HTTP API, Gateway, admin dashboard, uploads, search and voice signalling in Docker containers on one machine. Allow about 30 minutes, most of it spent downloading images.
@@ -27,11 +37,11 @@ By the end you have a Fluxer instance on a hostname you own, running the web app
| Outbound | Working DNS resolution from inside the containers |
| Host tools | `curl` and `openssl` on Linux. macOS ships both. The Windows installer needs neither |
Memory limits are ceilings, not reservations. On a 4 GB host, lower the `api` and `worker` limits first. With Docker Desktop, check the RAM assigned to its Linux virtual machine rather than the host's total.
Memory limits are ceilings. On a 4 GB host, lower the `api` and `worker` limits first. With Docker Desktop, check the RAM of its Linux virtual machine.
The stack is one Compose project. The edge and LiveKit are the only services that publish ports.
The edge and LiveKit are the only services that publish ports.
The steps below use the bundled Caddy, which obtains and renews a TLS certificate for the hostname and needs no configuration. To put your own proxy in front, add the `docker-compose.proxy.yml` overlay. The stack then leaves 80 and 443 alone and publishes one plain HTTP port for your proxy to forward to. [Behind your own reverse proxy](/operator/reverse-proxy/) has the overlay, the requirements, and worked configuration for nginx, Caddy, Traefik, HAProxy, Apache, a Cloudflare Tunnel and Nginx Proxy Manager.
The steps below use the bundled Caddy, which obtains and renews a TLS certificate for the hostname. To put your own proxy in front, add the `docker-compose.proxy.yml` overlay. The stack then leaves 80 and 443 alone and publishes one plain HTTP port for your proxy to forward to. [Behind your own reverse proxy](/operator/reverse-proxy/) has the overlay, the requirements, and worked configuration for nginx, Caddy, Traefik, HAProxy, Apache, a Cloudflare Tunnel and Nginx Proxy Manager.
## Step 1: Install Docker
@@ -77,7 +87,7 @@ Open these ports on the host:
| 7881 | tcp | LiveKit media, published by the LiveKit container |
| 7882 | udp | LiveKit media, published by the LiveKit container |
A machine behind a home router needs 80, 443 and both LiveKit ports forwarded to it. The certificate is issued from the public internet, and voice media arrives on the LiveKit ports directly. Running your own reverse proxy changes only the first two. The proxy holds them, and the stack binds a plain HTTP port on the loopback. 7881 and 7882 have to reach the host either way, because voice media never goes through a proxy.
A machine behind a home router needs 80, 443 and both LiveKit ports forwarded to it. The certificate is issued from the public internet, and voice media arrives on the LiveKit ports directly. Behind your own reverse proxy, the proxy holds 80 and 443 and the stack binds a plain HTTP port on the loopback. 7881 and 7882 still have to reach the host.
For another port, open that one instead of 443 and read [Serving on another port](#serving-on-another-port).
@@ -120,9 +130,7 @@ Invoke-WebRequest https://fluxer.dev/install.ps1.sha256 -OutFile install.ps1.sha
Read the script before you run it. It writes `.env`, and that file holds every secret the instance has.
The run below uses the bundled TLS. Add `--tls proxy` when something else terminates TLS, and read [Behind your own reverse proxy](/operator/reverse-proxy/) first.
Then run it with the hostname from Step 2. `--email` is optional and sets the contact address on outgoing web push. It defaults to `admin@` and the hostname.
Run it with the hostname from Step 2. The command below uses the bundled TLS. When something else terminates TLS, add `--tls proxy` after reading [Behind your own reverse proxy](/operator/reverse-proxy/).
```bash
sh install.sh --domain chat.example.com
@@ -140,7 +148,7 @@ The run prints one line per phase and ends with the URL to open.
### Serving on another port
The installer writes an `.env` for `https` on `443` and has no flag for another port. The two lines below in `.env` move the instance to another port. `FLUXER_PUBLIC_PORT` sets the port of the public address, and `FLUXER_HTTPS_PORT` sets the host port the edge publishes HTTPS on:
The installer writes an `.env` for `https` on `443` and has no flag for another port. Set both lines below in `.env`. `FLUXER_PUBLIC_PORT` is the port of the public address, and every endpoint the services advertise follows it. `FLUXER_HTTPS_PORT` is the host port the edge publishes HTTPS on.
```ini
FLUXER_PUBLIC_PORT=8443
@@ -151,7 +159,7 @@ FLUXER_HTTPS_PORT=8443
docker compose up -d
```
`FLUXER_PUBLIC_PORT` is the port of the public address, and every endpoint the services advertise follows it. It does not move what the host publishes, so `FLUXER_HTTPS_PORT` has to name the same port. Move `FLUXER_PUBLIC_SCHEME` with them when the new port serves plain HTTP, and set `FLUXER_HTTP_PORT` instead of `FLUXER_HTTPS_PORT`. `.env.example` ships beside `.env` and writes out both complete recipes.
For plain HTTP on the new port, also set `FLUXER_PUBLIC_SCHEME=http`, and set `FLUXER_HTTP_PORT` in place of `FLUXER_HTTPS_PORT`. `.env.example` ships beside `.env` and writes out both complete recipes.
Host 80 stays published on the `https` recipe and still answers the ACME challenge. Let's Encrypt only ever connects to the public 80 or 443, so the certificate is issued if a router in front forwards public 80 to this host. Serve your own certificate from the `Caddyfile` when it cannot.
@@ -178,10 +186,6 @@ Leave `FLUXER_PUBLIC_ORIGIN` commented out, or keep it consistent with the publi
Run `--dry-run` first to see what a set of flags does. The PowerShell script takes the same flags as `-Domain`, `-Email` and so on, and has no `-AllowRoot`. [Upgrading](/operator/upgrading/#run-the-upgrade) has the flags that only `--update` and `--rollback` read, and the exit codes.
### The script is the reference
Read the [Linux and macOS installer](https://fluxer.dev/install.sh) or [Windows installer](https://fluxer.dev/install.ps1) before running it.
## Step 5: Check that it works
Watch the stack settle:
@@ -232,7 +236,7 @@ On a username instance the wizard shows the owner's [recovery kit](/operator/sig
Create the owner account with an email address at a domain you control. Email delivery is optional, and [Email](/operator/configuration/#email) sets it up at any time.
Once email is on, the address goes through a DNS check before the account exists. Email counts as on when the switch is set and the provider is `smtp` with a complete SMTP configuration, so `FLUXER_EMAIL_ENABLED=true` on its own does not turn the check on. The address domain has to publish an `MX` record, or an `A` or `AAAA` record as a fallback. A name that resolves on your own network alone, such as a `.lan`, `.internal` or `home.arpa` name, publishes neither, and the account form answers `That email domain cannot receive mail.` whatever the address looks like. Use a domain with public records, or leave email off.
Once email is on, registration checks that the address domain can receive mail. A `.lan`, `.internal` or `home.arpa` address fails. Use a domain with public records, or leave email off.
`.env.example` ships `FLUXER_EMAIL_ENABLED=false`, which marks every address verified at creation and sends no mail at all. A forgotten owner password therefore has no email reset. Record it, and register a passkey or a second admin account before you open registration.
@@ -240,10 +244,14 @@ Once email is on, the address goes through a DNS check before the account exists
Sign in to the admin dashboard at `https://chat.example.com/admin` with the account holding the wildcard ACL. The **Instance Config** page has everything the wizard asked, plus registration mode, approvals and integration keys. **Limit Config** holds the instance limits published to clients. **Voice Regions** and **Voice Servers** come seeded, so voice needs no setup there.
The desktop client opens the hosted web app for its release channel, so reach your own instance in a browser. [This feedback post](https://feedback.fluxer.com/p/641) tracks that, and is being worked on.
[Configuration](/operator/configuration/) lists every runtime setting and the environment variable each one overrides. [Deployment availability](/http-api/deployment-availability/) lists the routes that exist only on the hosted deployment.
## Connect the apps
The web app is at your instance address. The desktop app asks for an instance first. Enter the instance address, such as `chat.example.com`. One desktop app can hold accounts on several instances and switch between them. The mobile apps take the same address.
The Flathub build of the desktop app may not connect to an instance yet. Its update is pending. To skip the wait, uninstall the Flathub copy and install our own Flatpak from [Linux repositories](/downloads/linux-repositories/#flatpak). It uses the same application id, `app.fluxer.Fluxer`.
## Backups
Recovery requires `.env`, a database dump and a backup of `seaweedfs-data`, which holds uploads, avatars, reports and harvests. See [Volumes and buckets](/operator/configuration/#volumes-and-buckets) for everything that needs backing up.
@@ -302,7 +310,7 @@ cd ~/fluxer
sh install.sh --update
```
`--update` records the running images, backs up the database and the uploads, refreshes the stack files, pulls, recreates, and verifies. It leaves every secret in `.env` untouched. On Windows it is `.\install.ps1 -Update`. Run `sh install.sh --update --dry-run` first to see the plan.
On Windows it is `.\install.ps1 -Update`.
[Upgrading](/operator/upgrading/) covers what the backup holds, rolling back, pinning a release and reclaiming disk.
@@ -4,13 +4,23 @@ title: Behind your own reverse proxy
description: Serving a Fluxer instance from nginx, Caddy, Traefik, HAProxy, Apache, or a tunnel.
---
:::tip[Plutonium and donations fund Fluxer]
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer). The Operator Pass is coming, and adds a direct line to the team for help and feedback.
:::tip[The Operator Pass is coming]
The [Operator Pass](https://fluxer.app/pass) gives you a direct line to the Fluxer team. It goes on sale in early November 2026 for $199 or €199, paid once. The price goes up on 1 January 2027. Pass holders get these perks for life.
- A private channel in Fluxer Labs where the team answers questions about your instance
- The Operator role in Fluxer Labs
- An Operator Pass profile badge
- Invitations to test new features on your instance
- Your avatar and name on the Fluxer website, if you want
The pass unlocks nothing in the software, and self-hosting stays free. If you have Visionary, you already have the pass.
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer).
:::
Fluxer runs behind any proxy that terminates TLS and forwards WebSocket upgrades.
The stack ships Caddy and runs it by default on `80` and `443`. One extra Compose file stops that and publishes a single plain HTTP port instead. That port already routes every path to the right internal service, so the proxy in front needs one routing rule: send everything to it.
The stack ships Caddy and runs it by default on `80` and `443`. One extra Compose file stops that and publishes a single plain HTTP port. That port routes every path to the right internal service. The proxy in front forwards everything to it unchanged.
## Enable the overlay
@@ -26,7 +36,7 @@ Or set `COMPOSE_FILE` in `.env` once and keep typing plain `docker compose` comm
COMPOSE_FILE=docker-compose.yml:docker-compose.proxy.yml
```
On a first install, `sh install.sh --tls proxy` writes that line and `FLUXER_EDGE_BIND` into `.env` for you, so there is nothing to add by hand. [Installer flags](/operator/get-started/#installer-flags) lists it with the rest.
On a first install, `sh install.sh --tls proxy` writes that line and `FLUXER_EDGE_BIND` into `.env`. [Installer flags](/operator/get-started/#installer-flags) lists it with the rest.
The port binds `127.0.0.1:8080` by default. `FLUXER_EDGE_BIND` sets both the interface and the host port. Move the port when something else on the host already holds `8080`:
@@ -48,10 +58,6 @@ curl -i http://127.0.0.1:8080/_health
`/_health` returns `200 OK` from the edge itself without reaching an upstream, so it is the health check to give your proxy.
:::note[There is nothing to configure inside the instance]
Forward all paths unchanged to the edge. No internal routing changes are needed.
:::
## What every proxy must do
#### Terminate TLS and serve the hostname over HTTPS
@@ -121,15 +127,9 @@ FLUXER_PUBLIC_SCHEME=https
FLUXER_PUBLIC_PORT=443
```
They stay `https` on `443` even though the instance itself speaks plain HTTP on `8080`. Clients read every base URL from the discovery document the API builds out of these values.
They stay `https` on `443` though the edge speaks plain HTTP on `8080`. Clients read every base URL from the discovery document the API builds from these values.
Serving on a port other than `443` means changing one of those variables:
```ini
FLUXER_PUBLIC_PORT=8443
```
Your proxy holds the public port, and the overlay pins the edge to plain HTTP on `8080` whatever that port is, so nothing else in `.env` moves with it.
To serve on another public port, change `FLUXER_PUBLIC_PORT` alone. The proxy holds that port, and the overlay keeps the edge on `8080`.
Leave `FLUXER_PUBLIC_ORIGIN` commented out, or keep it consistent with all three settings. Conflicting addresses can break sign-in and setup. See [The public origin](/operator/configuration/#the-public-origin).
@@ -455,7 +455,7 @@ The edge reads the variable at container start, so apply a change with `docker c
## Caching in front of Fluxer
Media reads are the only traffic worth caching, and the instance expects no cache in front of it. Every rule below is a correctness rule rather than a tuning choice, and a cache that cannot follow one should not store media at all.
Media reads are the only traffic worth caching, and the instance expects no cache in front of it. A cache that cannot follow every rule below must not store media.
#### Leave the signature parameters out of the cache key
@@ -489,7 +489,7 @@ Every media 200 is `public, max-age=31536000` with no `ETag` and no `Last-Modifi
## Turning the signature policy on
`FLUXER_MEDIA_PROXY_ATTACHMENT_SIGNATURE_MODE` is the instance switch, and a proxy that verifies signatures has one of its own. Both sides name the same three states, `off`, `report`, and `enforce`. Both read their setting once at start, so apply an instance change with `docker compose up -d media-proxy`, which replaces the container. `docker compose restart media-proxy` reuses the old environment and changes nothing.
`FLUXER_MEDIA_PROXY_ATTACHMENT_SIGNATURE_MODE` is the instance switch, and a proxy that verifies signatures has one of its own. Both sides name the same three states, `off`, `report`, and `enforce`. Apply an instance change with `docker compose up -d media-proxy`.
Turn the policy on in this order, and stop wherever a refusal appears that you did not expect:
@@ -547,4 +547,4 @@ FLUXER_CSP_EXTRA_CONNECT_SRC=wss://livekit.example.com
The policy entry is the origin alone, with no port or path. The hostname needs a valid TLS certificate and must reach the `/livekit` route on the edge with WebSocket upgrades. The media ports above never belong in the policy, because WebRTC media is not governed by `connect-src`. A separate hostname is rarely needed, since media goes to the address LiveKit advertises, not to a hostname.
`api` writes `FLUXER_LIVEKIT_URL` into the default voice server at start, and `app-proxy` builds the policy at container start, so apply the change with `docker compose up -d api app-proxy`. `docker compose restart` reuses the existing containers with their old environment. [Content Security Policy](/operator/configuration/#content-security-policy) has the other variables.
`api` writes `FLUXER_LIVEKIT_URL` into the default voice server at start, and `app-proxy` builds the policy at container start. Apply the change with `docker compose up -d api app-proxy`. [Content Security Policy](/operator/configuration/#content-security-policy) has the other variables.
@@ -4,13 +4,13 @@ title: Sign-in methods
description: Usernames or email addresses as the way members sign in, recovery kits, and admin reset links.
---
A self-hosted instance signs members in with a username or with an email address. A new instance uses usernames unless SMTP is set up. The method is chosen once, before setup is complete and before the first account exists, and it cannot change after that.
A self-hosted instance signs members in with a username or with an email address. A new instance uses usernames unless the email switch is on. The method is chosen once, before setup is complete and before the first account exists, and it cannot change after that.
## Usernames
Usernames are the default on a new instance. Members register with a username and a password. The instance never asks for an email address and stores none. It sends no email at all and needs no SMTP server.
Every username is unique, and members sign in with the username alone. A username instance never uses tags, as [username tags](#username-tags) describes.
Every username is unique, and members sign in with the username alone.
A forgotten password is recovered with a [recovery kit](#recovery-kits), or with an [admin reset link](#admin-reset-links) when the kit is gone too.
@@ -35,13 +35,13 @@ Bot accounts keep their random discriminators, and the apps and the admin dashbo
### Random tags
Every account gets a random tag of four digits, such as `alex#4821`. Several members can share a name. This is how every instance worked before tag styles existed. Random tags need email sign-in.
Every account gets a random tag of four digits, such as `alex#4821`. Several members can share a name. Random tags need email sign-in.
Members can change their tag after confirming their password or second factor, where the custom tag perk allows it. A tag someone else holds returns `TAG_ALREADY_TAKEN`.
## Email
Members register and sign in with an email address. This is how every instance worked before username sign-in existed. Email verification and password recovery send mail. An email instance needs SMTP set up under [Email](/operator/configuration/#email). Without SMTP, every address is marked verified at registration and a forgotten password has no reset path.
Members register and sign in with an email address. Email verification and password recovery send mail. An email instance needs SMTP set up under [Email](/operator/configuration/#email). Without SMTP, every address is marked verified at registration and a forgotten password has no reset path.
## Choosing the method
@@ -49,9 +49,9 @@ The setup wizard asks how members sign in, straight after the theme step and bef
When Email is picked, the same step asks how usernames are tagged. No tags is the recommended choice.
To decide before the first start, set `FLUXER_ACCOUNT_IDENTITY` to `username` or `email` in `.env`. For an email instance, set `FLUXER_TAG_STYLE` to `none` or `random`. A username instance ignores `FLUXER_TAG_STYLE`. The API reads them once, on the first start of a new instance, and stores the result. Without `FLUXER_ACCOUNT_IDENTITY`, a new instance with SMTP set up starts as an email instance with the tag style from `FLUXER_TAG_STYLE`, and any other new instance starts as a username instance. The wizard can still change the stored choice until setup is complete or the first account exists. An instance stored as already in use never offers the choice.
To decide before the first start, set `FLUXER_ACCOUNT_IDENTITY` to `username` or `email` in `.env`. For an email instance, set `FLUXER_TAG_STYLE` to `none` or `random`. A username instance ignores `FLUXER_TAG_STYLE`. The API reads them once, on the first start of a new instance, and stores the result. Without `FLUXER_ACCOUNT_IDENTITY`, a new instance starts on email when the [email switch](/operator/configuration/#email) is on and on usernames when it is not. The wizard can still change the stored choice until setup is complete or the first account exists. An instance stored as already in use never offers the choice.
The method and the tag style are fixed once the instance has its first account or setup is complete. The Instance Config page in the admin dashboard shows them, read-only. Nothing changes them later.
The Instance Config page in the admin dashboard shows the method and the tag style, read-only.
The hosted service at `fluxer.app` always uses email.
@@ -63,7 +63,7 @@ An instance that was running before this release stays on email with random tags
- Setup is marked complete, in the database or through `FLUXER_INSTANCE_SETUP_CONFIGURED`.
- The first admin was already granted.
An instance with none of these is new. It starts on the value of `FLUXER_ACCOUNT_IDENTITY` when that is set. Otherwise it starts on email when email delivery is switched on, through `FLUXER_EMAIL_ENABLED` or the admin dashboard, and on usernames when it is not. The setup wizard can still change the choice on a new instance.
An instance with none of these is new, and starts as [Choosing the method](#choosing-the-method) describes.
When that check cannot read the database, the API stores nothing and the instance behaves as an email instance. The next start runs the check again.
@@ -108,7 +108,7 @@ A guild ban on an email instance also blocks the banned account's email address,
## Apps
The web app an instance serves supports both methods. A Fluxer app built before username sign-in only offers email sign-in, and it checks that the value looks like an email address. The mobile app is one of them until an update adds username sign-in.
The web, desktop and mobile apps support both methods. A Fluxer app built before username sign-in only offers email sign-in, and it checks that the value looks like an email address.
Members on such an app sign in with the username, `@` and the instance host, such as `[email protected]`, until the app is updated. The instance host is the host of the instance web address, of any address in `FLUXER_APP_ORIGIN_ALIASES` or of `FLUXER_DOMAIN`, in any letter case and with or without a port. These apps expect a dot in the host, so an instance at a host without one, such as `localhost`, cannot be reached this way.
@@ -4,8 +4,18 @@ title: Upgrading
description: Upgrading and rolling back an instance with the installer, what the backup covers, and how to restore it.
---
:::tip[Plutonium and donations fund Fluxer]
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer). The Operator Pass is coming, and adds a direct line to the team for help and feedback.
:::tip[The Operator Pass is coming]
The [Operator Pass](https://fluxer.app/pass) gives you a direct line to the Fluxer team. It goes on sale in early November 2026 for $199 or €199, paid once. The price goes up on 1 January 2027. Pass holders get these perks for life.
- A private channel in Fluxer Labs where the team answers questions about your instance
- The Operator role in Fluxer Labs
- An Operator Pass profile badge
- Invitations to test new features on your instance
- Your avatar and name on the Fluxer website, if you want
The pass unlocks nothing in the software, and self-hosting stays free. If you have Visionary, you already have the pass.
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer).
:::
An upgrade moves an instance to a newer release. `install.sh --update` does all of it: back up, download the new stack files, pull the new images, recreate the containers that changed. The stack files are the compose files, the `Caddyfile` and `.env.example`. Allow about twenty minutes, most of it the backup and the pull.
@@ -33,7 +43,7 @@ The stack files on `main` can run ahead of the `v1` images. The current `docker-
| Step | What it does |
| --- | --- |
| Mint | Writes any key the refreshed stack requires that `.env` does not hold, listed under [Run the upgrade](#run-the-upgrade) |
| Mint | Writes any key the refreshed stack requires that `.env` does not hold, listed below |
| Record | Writes the image references, the image ID each container has, and the tag `.env` names, into a new record directory |
| Save | Copies `.env` and the stack files into that record |
| Dump | Dumps the database with the stack still serving, and checks the custom-format header on the result |
@@ -47,45 +57,27 @@ The stack files on `main` can run ahead of the `v1` images. The current `docker-
A failed run leaves the instance running on the images it already had.
`docker compose up -d` does not notice a changed `Caddyfile`. The script restarts `edge` by name to pick it up.
An instance set up before the edge served LiveKit at `/livekit` needs one edit that the upgrade does not make. Until you make it, voice does not connect. [Voice signalling moved to /livekit](#voice-signalling-moved-to-livekit) has the edit.
The refreshed `docker-compose.yml` renames the `caddy` service to `edge`, and the two publish the same host ports. `--remove-orphans` takes the old container down in the same call, so the new one can bind them. Without it the step stops with `Bind for 0.0.0.0:443 failed`. It also removes any container in the project whose service the loaded Compose files no longer define, so keep `COMPOSE_FILE` the same across an upgrade. [Keep a local compose change](#keep-a-local-compose-change) has the file layout that survives one. [When the compose file list names a missing file](#when-the-compose-file-list-names-a-missing-file) has the error Compose prints when `COMPOSE_FILE` names a file that does not exist.
The rename also moves the `caddy-data` and `caddy-config` volumes to `edge-data` and `edge-config`, so the old two are left unused and the edge requests its certificate again on the first start.
Upgrades change `FLUXER_IMAGE_TAG` and add missing required secrets. Existing values are preserved, except for the unusable upload-relay placeholder described below.
Upgrades change `FLUXER_IMAGE_TAG` and write any of the three secrets below that `.env` lacks or holds as `CHANGE_ME`. Every other value in `.env` is kept.
The refreshed stack requires `FLUXER_ERLANG_COOKIE`. `--update` generates a missing value as 64 hex characters. Without it, Compose commands fail with `set FLUXER_ERLANG_COOKIE in .env`.
- `FLUXER_ERLANG_COOKIE`.
- `FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64`. It must decode to at least 32 bytes.
- `FLUXER_PROFILE_PSEUDONYM_SECRET`.
To write it by hand, run the generator in a shell:
A missing one stops every Compose command with `set <name> in .env`. To write one by hand, run its line in a shell:
```bash
printf '\nFLUXER_ERLANG_COOKIE=%s\n' "$(openssl rand -hex 32)" >> .env
```
Do not paste `FLUXER_ERLANG_COOKIE=$(openssl rand -hex 32)` into `.env`. Compose does not execute shell commands in that file.
`api` and `media-proxy` require `FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64` to decode to at least 32 bytes. `--update` replaces a missing or `CHANGE_ME` value with a generated secret. Both services must use the same value.
To write it by hand, run the generator in a shell the same way:
```bash
printf '\nFLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64=%s\n' "$(openssl rand -base64 32)" >> .env
```
The refreshed stack requires `FLUXER_PROFILE_PSEUDONYM_SECRET` on `api`, `worker`, and `users-shard`. `--update` replaces a missing or `CHANGE_ME` value with 64 hex characters. Without it, Compose commands fail with `set FLUXER_PROFILE_PSEUDONYM_SECRET in .env`.
To write it by hand, run the generator in a shell the same way:
```bash
printf '\nFLUXER_PROFILE_PSEUDONYM_SECRET=%s\n' "$(openssl rand -hex 32)" >> .env
```
## The script is the reference
Read the [Linux and macOS installer](https://fluxer.dev/install.sh) or [Windows installer](https://fluxer.dev/install.ps1) before running it.
Do not paste `FLUXER_ERLANG_COOKIE=$(openssl rand -hex 32)` into `.env`. Compose does not execute shell commands in that file.
## Keep a local compose change
@@ -97,9 +89,7 @@ The supported way to hold a local choice is a separate file, listed in `COMPOSE_
COMPOSE_FILE=docker-compose.yml:docker-compose.proxy.yml:local.compose.yml
```
Compose merges the files left to right, so `local.compose.yml` wins over the ones before it. An upgrade refreshes the stack files and nothing else, so a file outside that set survives every upgrade untouched. A record copies `.env` and those files, and no other file from the working directory. An override file is never backed up with them, so keep it wherever the rest of the configuration lives.
Keep environment settings in `.env`. Upgrades preserve them apart from the tag and required-secret changes described above.
Compose merges the files left to right, and `local.compose.yml` wins over the ones before it. An upgrade replaces only the stack files, and a file outside that set survives it. A record copies only `.env` and the stack files. Back up an override file yourself.
[Enable the overlay](/operator/reverse-proxy/#enable-the-overlay) has the overlay this is most often used for. [Docker labels](/operator/reverse-proxy/#docker-labels) has a worked third file.
@@ -316,7 +306,7 @@ docker compose exec -T postgres sh -c 'pg_restore -U $POSTGRES_USER -d $POSTGRES
docker compose up -d
```
`--clean` prints notices about objects that do not exist yet, which is expected against a fresh directory. The role and database come from the `postgres` container's environment, which follows `FLUXER_POSTGRES_USERNAME` and `FLUXER_POSTGRES_DATABASE`, the same way the installer's dump reads them. These commands are for the bundled database. A database outside the stack restores with its own tools.
`--clean` prints notices about objects that do not exist yet, which is expected against a fresh directory. These commands are for the bundled database, like the dump in [Backups](/operator/get-started/#backups). A database outside the stack restores with its own tools.
PowerShell has no `<` redirection. On Windows, copy the dump into the container and name it as a file:
@@ -339,7 +329,7 @@ docker run --rm -v fluxer_seaweedfs-data:/data \
docker compose up -d
```
For a `seaweedfs-data.tar`, write `tar xf` in place of `tar xzf`. `tar` extracts over whatever is already on the volume, so the `find` empties it first. In PowerShell write `${PWD}` instead of `$PWD`. Success is an existing attachment URL answering 200 again. The `fluxer_` prefix is the Compose project name, which `docker-compose.yml` sets to `fluxer`.
For a `seaweedfs-data.tar`, write `tar xf` in place of `tar xzf`. `tar` extracts over whatever is already on the volume. The `find` empties it first. In PowerShell write `${PWD}` in place of `$PWD`. Success is an existing attachment URL answering 200 again.
## Move to a new Postgres major version