Do you self host a suite of containerized web applications and struggle to keep friends and family up to date on what's available and where? Flip-Flop might be the tool for you. It's goal is simple, give users one page to bookmark where they can actually use the applications they want. Flip-Flop uses docker labels to bring all your web interfaces into a tabbed structure with additional features to help communicate things like scheduled maitinance to users.
checkout the Demo instance!
- Tabbed interface for easy navigation between apps.
- Customizeable themes, favicons, etc.
- Responsive design for desktop and mobile compatibility. There's room to improve here.
- Banner alerts to communicate with users
- multiple instance support; run as many instances of flip-flop on one host as you like with different content
- minimal if any configuration required. All options available as an environment variable or yaml
version: "3.8"
services:
flip-flop:
image: ghcr.io/mullinmax/flip-flop:main
restart: unless-stopped
ports:
- "80:80"
volumes:
- "flip-flop-data:/config" # optionally add config.yaml for configuration
- "/var/run/docker.sock:/var/run/docker.sock:ro" #mount your docker socket as read only
environment:
# Sets the page title (what the tab name is)
- FLIP_FLOP_NAME=Maxwell's Dashboard
# sets the name of the instance, defaults to "default"
# allows for multiple flip-flops to run on the same system and have different content
- FLIP_FLOP_INSTANCE=main
# Banner information
- FLIP_FLOP_BANNER_TITLE=Scheduled Downtime 1/1/23
- FLIP_FLOP_BANNER_BODY=Expect services to be down for scheduled maitinance 1pm-5pm
# Use to override default
#- FLIP_FLOP_FAVICON=/config/custom_favicon.ico
#- FLIP_FLOP_THEME=/config/custom_theme.css
# Sets internal port number, defaults to 80
#- FLIP_FLOP_PORT=80
# Use if your setup requires for some reason
#- FLIP_FLOP_DOCKER_SOCKET_PATH=/var/run/docker.sock
volumes:
flip-flop-data:
Optionally any configuration variable can be set via config.yaml
file instead of environment variables. You can even mix-and-match configuration vs env variables. If for example you have two instances with different ports or names you could define those in the environment variables and define things like theme or docker socket path in your config file. Flip-Flop will always first consider environment variables, then the config file and finally defautls. Here is an example setup:
# /config/config.yaml
# Sets the page title (what the tab name is)
FLIP_FLOP_NAME: "Maxwell's Dashboard"
# Sets the name of the instance, defaults to "default"
# Allows for multiple flip-flops to run on the same system and have different content
FLIP_FLOP_INSTANCE: "main"
# Banner information
FLIP_FLOP_BANNER_TITLE: "Scheduled Downtime 1/1/23"
FLIP_FLOP_BANNER_BODY: "Expect services to be down for scheduled maintenance 1pm-5pm"
# Use to override defaults
# FLIP_FLOP_FAVICON: "/config/custom_favicon.ico"
# FLIP_FLOP_THEME: "/config/custom_theme.css"
# Sets internal port number, defaults to 80
# FLIP_FLOP_PORT: 80
# Use if your setup requires for some reason
# FLIP_FLOP_DOCKER_SOCKET_PATH: "/var/run/docker.sock"
Flip-Flop parses labels on your docker containers to figure out what tabs it should show in the web UI. Here's an example of how they are defined:
version: "3.8"
networks:
default:
external: true
name: "traefik_default"
services:
uptime-kuma:
image: louislam/uptime-kuma:latest
labels:
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime.doze.dev`)"
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
# allow iframes: see common issues before using
#- "traefik.http.routers.uptime-kuma.middlewares=uptime-kuma-modify-headers"
#- "traefik.http.middlewares.uptime-kuma-modify-headers.headers.customresponseheaders.X-Frame-Options="
- "flip-flop.main.name=Status Dashboard"
- "flip-flop.main.priority=5"
# note that for url and icon I chose not to include main
# this makes these fields apply to all instances that parse the container
# This way I onny need to redefine priority and name to add this to another instance
- "flip-flop.url=https://uptime.doze.dev/status/plex"
# you only need to define this if you don't want to use the app's favicon. You can use an emoji
# in the future this will support custom paths to image files
- "flip-flop.icon=📈"
volumes:
- "uptime-kuma-data:/app/data"
volumes:
uptime-kuma-data:
Flip-Flop uses iframes in order to allow users to switch between apps without leaving the central page. For good reason, many web applications disable being put into iframes. This prevents Click jacking. The example above includes labels you can use when using traefik as a reverse proxy to allow your app to be put into an iframe. Carefully consider how this impacts your security of yourself and your users. Use at your own risk. Thankfully many apps do not have this constraint so you don't have to do this often.
Flip-Flop does it's best to automatically grab the best favicon from each app to use as the icon in the menu. Some common causes for it not correctly grabbing the favicon are:
- The app url gets redirected (flip-flop does not currently follow redirects). For example If you host Navidrome at
https://music.domain.com
it will automatically redirect tohttps://music.domain.com/app/
. You will need to set the flip flop URL to this second url for the favicon to work. - The app has basic http authentication enabled. In order for the favicon to be retreived Flip-Flop would need to log into the app. As a rule Flip-Flop is not designed to handle security critical things like passwords so it does not support this.
- leaving off the
https://
orhttp://
from the url.
Contributions are welcome. Please feel free to submit pull requests or open issues for improvements and bug fixes. This project is being actively developed and I would love to adapt this to something that's as useful to as many people as possible. I would especially love some help refining the CSS styles and adding some great themes.
A development instance is available here this instance will track the main branch.
This project is licensed under the MIT License - see the LICENSE file for details.