Skip to content

Config Branding

Dejan Strbac edited this page Nov 12, 2026 · 1 revision

This page covers the [branding] section of the configuration file: the colour theme for users who have not picked one, and the logo in the edelweiss's place. It goes through each key and what it changes in the page, how a custom logo's files are served, the errors that stop startup, and how to check the result. Without a [branding] section, ALPS looks as it ships: the Alps theme and the edelweiss logo. The reference is CONFIGURATION.md, section 10.

Keys

Key Default Accepts What it changes
default_theme "alps" "alps", "migadu", "nord", "ocean" The colour theme of the sign-in page, and of every user who has not picked a theme in Settings
logo The default theme's own logo, else the edelweiss "alps", "migadu", or the path of a folder holding a favicon package The logo on the sign-in page and in the header, the browser tab icon, and the icons for home screen shortcuts and installed apps

ALPS trims spaces from both values. Theme names and built-in logo names are not case-sensitive, so " Nord " means "nord". An empty string counts as leaving the key out. A key ALPS does not know, such as theme = "nord", is ignored, and the startup log warns Unknown configuration key: branding.theme (ignored).

[branding]
default_theme = "nord"
logo = "/etc/alps/logo"

default_theme

The four themes are the ones a user can choose under Settings > Appearance > Color Theme: Alps, Migadu, Nord and Ocean. Each theme has a light and a dark variant. Each user's Theme Mode setting picks between them: Light, Dark, or System Auto (the default). So default_theme sets the palette, and each user still chooses light or dark. The Migadu theme also changes the fonts and makes the corners squarer. The other themes change only the colours.

Who sees the default theme:

  • Users who have never picked a theme. Settings shows default_theme as their Color Theme. When you change default_theme, these users get the new theme.
  • Not users who have picked one. A user who picks a theme in Settings keeps that theme, also when it is the same as default_theme, so a later change of default_theme does not reach them. ALPS saves the choice with the user's settings on the server, so it follows the user to other browsers (Storage in IMAP METADATA). The selector has no entry for going back to the default.
  • The sign-in page. The theme is applied from the first paint. Each browser keeps the theme setting of the last user who signed in there, and the sign-in page uses it. If that user picked a theme, the sign-in page in that browser shows the picked theme rather than default_theme. A user who has never picked a theme and first signs in on that browser starts there with the same remembered theme.

default_theme = "migadu" also brings the Migadu logo unless logo is set. To keep the edelweiss in the Migadu theme, set logo = "alps".

logo

logo Logo on the page Tab, home screen and app icons
left out The Migadu mammoth with default_theme = "migadu", the edelweiss with any other theme The icons of that logo
"alps" The edelweiss ALPS's own icons
"migadu" The Migadu mammoth The Migadu icon set that ships with ALPS
A folder path The package's favicon.svg The package's files

ALPS draws the two built-in logos in the theme's colours on the page, so they change with the theme and with light or dark mode. The tab and home screen icons are fixed image files.

Where the logo appears

  • Above the sign-in form.
  • At the left of the header after sign-in, on screens wider than 768 pixels. On narrower screens the header has no logo.
  • As the browser tab icon, the icon of a bookmark or home screen shortcut, and the icon of ALPS when it is installed as an app.
  • On the notice ALPS shows when JavaScript is turned off.

The second step of a two-factor sign-in shows a fingerprint icon instead of the logo.

A favicon package

A favicon package is a folder with these six files:

File Used as
favicon.svg The logo on the page, and the tab icon in browsers that support SVG icons
favicon-96x96.png The PNG tab icon
favicon.ico The icon for browsers that ask for /favicon.ico
apple-touch-icon.png The home screen icon on iPhone and iPad (the page declares it as 180×180)
web-app-manifest-192x192.png, web-app-manifest-512x512.png The icons listed in site.webmanifest, used when ALPS is installed as an app

RealFaviconGenerator writes these file names, so you can use its output folder unchanged. When you build the package:

  • All six files must be there, and each can be at most 1 MiB (1,048,576 bytes). ALPS ignores any other files in the folder. That includes a site.webmanifest: ALPS keeps serving its own.
  • ALPS reads the files once, at startup, and serves them from memory. If you change a file in the folder, nothing changes until ALPS restarts.
  • Use an absolute path. ALPS resolves a relative path from the directory it was started in, not from the folder of the configuration file. The shipped systemd unit does not set a working directory.
  • The folder and its files must be readable by the user ALPS runs as. The systemd unit in dist/alps.service runs ALPS as alps with ProtectHome=true, which hides /home, /root and /run/user from it. Keep the package outside those, for example in /etc/alps/logo.
  • favicon.svg keeps its own colours. The page shows it as an image at the edelweiss's size, keeping its proportions. Unlike the built-in logos, it does not follow the theme or light and dark mode. Pick a design that is readable on both light and dark backgrounds.

logo does not take a URL. Put the package on the machine ALPS runs on: the page's Content-Security-Policy loads images only from ALPS itself (and data: and blob: URLs), and ALPS serves the package's files from its own paths (see How the branding reaches the browser).

Errors that stop startup

If [branding] has a mistake, ALPS refuses to start. It exits with status 1 and prints one of these lines on standard error:

Error generating options: branding.default_theme: unknown theme "solarized", expected one of alps, migadu, nord, ocean
Error generating options: branding.logo: "unicorn" is neither a built-in logo (alps, migadu) nor a folder holding a favicon package
Error generating options: branding.logo: "/etc/alps/logo/favicon.svg" is neither a built-in logo (alps, migadu) nor a folder holding a favicon package
Error generating options: branding.logo: the favicon package has no favicon.ico: stat /etc/alps/logo/favicon.ico: no such file or directory
Error generating options: branding.logo: "/etc/alps/logo/favicon.svg" is 1049600 bytes, more than the 1048576 an icon may be
Error generating options: branding.logo: open /etc/alps/logo/favicon.ico: permission denied

The third line means logo names a file instead of the folder that holds it. You get the same message for a folder that does not exist, or one that the ALPS user cannot see. The last line means the ALPS user cannot read that file. The theme error quotes the value as written, spaces and capitals included.

Under the shipped systemd unit, these lines are in journalctl -u alps, and systemd starts ALPS again every 5 seconds until the configuration is fixed.

How the branding reaches the browser

  • Meta tags in the page. ALPS adds <meta> tags to the <head> of the index.html it serves:

    • alps-default-theme holds the theme, whenever default_theme is set, "alps" included.
    • alps-logo-builtin holds a built-in logo other than the edelweiss.
    • alps-logo holds /favicon.svg?v= and a fingerprint of the package's six files (16 hex digits) when the logo is a package. The page loads its logo from that address, so a changed package gives the logo a new address.

    A logo is either built in or a package, so the page has at most two of these tags. The frontend reads them before anyone signs in, so the sign-in page is branded from its first paint.

  • Icons at the usual paths. A built-in logo other than the edelweiss, or a package, replaces ALPS's own icons at the same paths: /favicon.svg, /favicon-96x96.png, /favicon.ico, /apple-touch-icon.png, /web-app-manifest-192x192.png and /web-app-manifest-512x512.png. These files are served like the rest of the frontend, with Cache-Control: no-cache and an ETag, so a browser asks ALPS again before it reuses a stored copy. Replaced icons also get a Content-Security-Policy of their own, default-src 'none'; style-src 'unsafe-inline'; sandbox, so an SVG opened on its own in a tab runs no scripts.

  • Not in the dev server. The Vite dev server (npm run dev in frontend/) serves its own index.html, so configured branding does not appear there (README). Check branding against ALPS itself.

Applying a change

ALPS reads [branding] and the package files only at startup, so restart ALPS after changing either (systemctl restart alps). A SIGHUP only reopens the log file. That includes systemctl reload alps with the shipped unit, as the comment in the unit file says.

After the restart, every new page load gets the new branding. Tabs that are already open notice the change through the X-Alps-Build header, a hash of the index.html ALPS serves, which ALPS sends with every answer. They then offer the user a reload. The hash changes when you change default_theme, when you switch between the edelweiss, a built-in logo and a package, and when any of a package's six files changes, since the page carries their fingerprint. Replacing one package with another, or changing a file in the folder, therefore also offers open tabs a reload, once ALPS has restarted and read the files again.

Checking the result

  1. Look for the meta tags in the page:

    curl -s https://webmail.example.com/ | grep -o '<meta name="alps-[^>]*>'

    With default_theme = "migadu" and no logo, this prints:

    <meta name="alps-default-theme" content="migadu" />
    <meta name="alps-logo-builtin" content="migadu" />
    

    With no branding it prints nothing. With a package it prints a line such as <meta name="alps-logo" content="/favicon.svg?v=3f1c0a9b2d4e6f70" />, whose digits change with the package's files.

  2. For a package, check that ALPS serves your files:

    curl -s https://webmail.example.com/favicon.ico | cmp - /etc/alps/logo/favicon.ico && echo same
  3. Open the sign-in page in a private window, so the browser has no remembered theme, and check the theme and the logo. Then sign in, in a window wider than 768 pixels, and check the logo in the header.

Examples

The Migadu look, with its theme, logo and icons:

[branding]
default_theme = "migadu"

The Migadu theme with the edelweiss:

[branding]
default_theme = "migadu"
logo = "alps"

Your own logo on the Ocean theme:

[branding]
default_theme = "ocean"
logo = "/etc/alps/logo"

What [branding] does not change

  • The names. The tab title is Webmail, and the app name in site.webmanifest is Webmail, with a white theme_color and background_color.
  • The text on the pages. This includes "Sign in to your webmail." and the notice shown without JavaScript, which says "Alps Webmail".
  • The name a browser shows when a user adds a security key. Set that with [webauthn] display_name (default "Alps Webmail"). See Config Rate Limiting and WebAuthn.
  • Colours outside the four themes. No key sets custom colours.

For contributors: adding a theme or a built-in logo

ALPS checks names against fixed lists in Go, and tests keep those lists the same as the frontend's:

See also

Clone this wiki locally