- Table of contents
- Get FlatImage
- Usage
- Use cases
- Samples
- Usage Inside Docker
- Architecture
- Further Considerations
- Motivations
- Related Projects
FlatImage, is a hybrid of Flatpak sandboxing with AppImage portability.
FlatImage use case is twofold:
-
A tool to package software that aims to work across several linux distros, it bundles all the software dependencies and the software itself, within an executable; unlike
AppImage
, FlatImage runs the application in a container, which increases portability and compatibility at the cost of file size. -
A portable container image that requires no superuser permissions to run.
The diverse GNU/Linux
ecosystem includes a vast array of distributions, each
with its own advantages and use cases. This can lead to cross-distribution
software compatibility challenges. FlatImage addresses these issues by:
- Utilizing its own root directory, enabling dynamic libraries with hard-coded paths to be packaged alongside the software without binary patching.
- Running the application in its own gnu system, therefore, not using host libraries that might be outdated/incompatible with the application.
Feature | FlatImage | Docker | AppImage |
---|---|---|---|
No superuser privileges to use | x | x2 | x |
Overlayfs (allows to install programs even after compression) | x | ||
No installation necessary (click and use) | x | Requires docker on the host | x |
Requires building on an old system to minimize glibc issues | N/A | x | |
Mountable as a filesystem | x | x | x3 |
Runs without mounting the filesystem | x | ||
Straightforward build process | x | x | |
Desktop integration | x | x | |
Extract the contents | x | x | x |
Supports reconfiguration without rebuild | x | x (layers) | |
No host libraries used (Filesystem Isolation) | x | x | |
Supports compression of specific directories/files in the package | x | ||
Portable mutable user configuration | x | x | |
Granular control over containerization | x | x | |
Works without fuse installed (still requires kernel support) | x4 | x | x5 |
Layered filesystem | x (overlayfs) | x | |
Advanced networking management | x | ||
Advanced security features | x |
You can get the latest release here, and extract the compressed archive with your file manager or with tar -xf some-file.tar.xz
. To verify the image integrity, you can use the sha256sum
file that accompanies each release, like so: sha256sum -c some-file.flatimage.sha256sum
.
You can enter the container simply by executing the downloaded image, e.g.,
./arch.flatimage
, which should give you a prompt like this (flatimage@arch) →
.
Remember to resize the image as shown in the examples before installing programs
on it, else there won't be enough space for it.
To enter the container as root (to install software) use:
./arch.flatimage fim-root bash
Avaliable options:
- fim-compress: Compress the filesystem to a read-only format.
- fim-root: Execute an arbitrary command as root.
- fim-exec: Execute an arbitrary command.
- fim-cmd: Set the default command to execute when no argument is passed.
- fim-resize: Resizes the filesystem.
- # Resizes the filesytem to have 1G of size
- E.g.: ./arch.flatimage fim-resize 1G
- # Resizes the filesystem by current size plus 1G
- E.g.: ./arch.flatimage fim-resize +1G
- fim-mount: Mount the filesystem in a specified directory
- E.g.: ./arch.flatimage fim-mount ./mountpoint
- fim-xdg: Same as the 'fim-mount' command, however it opens the
mount directory with xdg-open
- fim-perms-set: Set the permission for the container, available options are:
pulseaudio, wayland, x11, session_bus, system_bus, gpu, input, usb
- E.g.: ./arch.flatimage fim-perms pulseaudio,wayland,x11
- fim-perms-list: List the current permissions for the container
- fim-config-set: Sets a configuration that persists inside the image
- E.g.: ./arch.flatimage fim-config-set home '"$FIM_FILE_BINARY".home
- E.g.: ./arch.flatimage fim-config-set backend "proot"
- fim-config-list: List the current configurations for the container
- E.g.: ./arch.flatimage fim-config-list # List all
- E.g.: ./arch.flatimage fim-config-list "^dwarfs.*" # List ones that match regex
- fim-dwarfs-add: Includes a dwarfs file inside the image, it is
automatically mounted on startup to the specified mount point
- E.g.: ./arch.flatimage fim-dwarfs-add ./image.dwarfs /opt/image
- fim-dwarfs-list: Lists the dwarfs filesystems in the flatimage
- E.g.: ./arch.flatimage fim-dwarfs-list
- fim-hook-add-pre: Includes a hook that runs before the main command
- E.g.: ./arch.flatimage fim-hook-add-pre ./my-hook
- fim-hook-add-post: Includes a hook that runs after the main command
- E.g.: ./arch.flatimage fim-hook-add-post ./my-hook
- fim-help: Print this message.
FIM_NAME
: Name of the package, useful for desktop integration (default is flatimage-$FIM_DIST)FIM_ICON
: Path to the application icon, default is '"$FIM_DIR_MOUNT"/fim/desktop/icon.svg'FIM_BACKEND
: Back-end to use, default isbwrap
,proot
is also supported.FIM_COMPRESSION_LEVEL
: Compression level of dwarfs (0-9), default is 6FIM_SLACK_MINIMUM
: Free space always available on the filesystem startup, automatically grows it gets past it in the previous execution, default is 50000000 bytes (50MB).FIM_COMPRESSION_DIRS
: Directories to compress with dwarfs, default is/usr /opt
.FIM_DEBUG
: If defined to 1, print debug messages.FIM_FIFO
: If defined to 1, use FIFO when stdout/stderr are not connected to a terminal, default is 1.
FIM_DIST
: The linux distribution name (alpine, arch, ubuntu)FIM_FILE_BINARY
: Full path to the executed binary fileFIM_BASENAME_BINARY
: Basename of the executed binary file.FIM_DIR_BINARY
: The path to the directory of the executed binary file.FIM_DIR_TEMP
: Location of the temporary runtime directory.FIM_DIR_MOUNT
: Location of the runtime fim mountpoint.FIM_MAIN_OFFSET
: Shows filesystem offset and exits.FIM_DIR_HOST_CONFIG
: Configuration directory in the host machineFIM_DIR_HOST_OVERLAYS
: Overlayfs mountpoint directory in the host machine
The default path of FIM
temporary files is /tmp/fim
.
It is possible to change the default home path with fim-config-set home
,
e.g.:
# Default, uses the host's home directory
$ ./arch.flatimage fim-config-set home '$HOME'
# The name of the flatimage binary plus an appended ".home"
$ ./arch.flatimage fim-config-set home '"$FIM_FILE_BINARY".home'
Besides the environment variable FIM_BACKEND
, it is possible to use the
fim-config-set backend
to set the default tool. The environment variable
always takes precedence if defined.
# Uses bwrap as the backend (default)
$ ./arch.flatimage fim-config-set backend "bwrap"
# Uses proot as the backend
$ ./arch.flatimage fim-config-set backend "proot"
# Run command on host using a static bash binary
$ ./arch.flatimage fim-config-set backend "host"
Flatimage supports desktop integration, the icon and menu entry should appear
after the first execution. Make sure to have this line in your ~/.bashrc
file:
export XDG_DATA_DIRS=$HOME/.local/share:$XDG_DATA_DIRS
After including it, log out and log in again (or reboot) for the changes apply. Here's how to configure flatimage desktop integration:
# Set the name of your application
$ ./arch.flatimage fim-config-set name "MyApp"
# Set the icon, supported image types are '.svg,.png,.jpg'
$ ./arch.flatimage fim-config-set icon '"$FIM_DIR_MOUNT"/fim/desktop/icon.png'
# Copy icon to inside the container
$ ./arch.flatimage fim-root cp ./my-image.png /fim/desktop/icon.png
# Set the categories of your application
# Avaliable categories found here: https://specifications.freedesktop.org/menu-spec/latest/apa.html
$ ./arch.flatimage fim-config-set categories "Game"
# Enable desktop integration
$ ./arch.flatimage fim-config-set desktop 1
You can also disable desktop integration with:
# Disable desktop integration
$ ./arch.flatimage fim-config-set desktop 0
To erase all desktop entries and icons created by flatimage, you can use the command:
$ find ~/.local/share -iname "*flatimage*" -exec rm -v "{}" \;
Flatimage redirects xdg-open
commands to the host machine
Examples:
- Open a video file with the host default video player:
xdg-open my-file.mkv
- Open a link with the host default browser:
xdg-open www.google.com
Overlayfs is automatically enabled for all compressed filesystems.
You can include bash
hooks to execute code before and/or after your program:
# Include hook
$ ./arch.flatimage fim-hook-add-pre ./my-pre-hook
This is an example of a pre-hook file:
export MY_VAR="hello there, I'm defined inside flatimage!"
echo "Starting my cool program"
if [[ -v MY_OPTION ]]; then
echo "You passed the option: ${MY_OPTION}!"
fi
To remove the hook, just use:
./arch.flatimage fim-exec rm /fim/hooks/pre/my-pre-hook
... or enter the container, cd /fim/hooks/pre
and erase the files.
To insert a post hook, just use the directory post
instead.
# Include hook
$ ./arch.flatimage fim-hook-add-post ./my-post-hook
Flatimage has a portal mechanism to dispatch commands to the host machine.
Examples:
- Open thunar in the host machine:
fim_portal_guest thunar
- Open thunar in the host machine (full path):
fim_portal_guest /bin/thunar
- Open the desktop folder with thunar on the host machine:
fim_portal_guest thunar ~/Desktop
To use FlatImage there is no need to install anything, simply download an image in
the releases page, i.e., focal (ubuntu)
, alpine
or arch
. The archive is compressed, extract it and use it
as shown in the following examples.
# Set the maximum filesystem size (use du -sh ./arch.flatimage to see actual size)
$ ./arch.flatimage fim-resize 4G
# Set the desired permissions (you can also list them with fim-perms-list)
$ ./arch.flatimage fim-perms-set wayland,pulseaudio,gpu,session_bus
# Install the desired application in the ubuntu subsystem
$ ./arch.flatimage fim-root fakechroot pacman -S firefox --noconfirm
# Test the application
$ ./arch.flatimage fim-exec firefox
# Set the default startup command
$ ./arch.flatimage fim-cmd firefox
# (optional) Compress the package filesystem
$ ./arch.flatimage fim-compress
# (optional) Rename the binary to the main application name
mv arch.flatimage firefox
# Run the application (you can also click on it in your file manager)
$ ./firefox
# Set the maximum filesystem size (use du -sh ./focal.flatimage to see actual size)
$ ./focal.flatimage fim-resize 4G
# Set the desired permissions (you can also list them with fim-perms-list)
$ ./focal.flatimage fim-perms-set wayland,pulseaudio,gpu,session_bus
# Install the desired application in the ubuntu subsystem
$ ./focal.flatimage fim-root apt install -y firefox
# Test the application
$ ./focal.flatimage fim-exec firefox
# Set the default startup command
$ ./focal.flatimage fim-cmd firefox
# (optional) Compress the package filesystem
$ ./focal.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv focal.flatimage firefox
# Run the application (you can also click on it in your file manager)
$ ./firefox
# Set the maximum filesystem size (use du -sh ./alpine.flatimage to see actual size)
$ ./alpine.flatimage fim-resize 2G
# Set the desired permissions (you can also list them with fim-perms-list)
$ ./alpine.flatimage fim-perms-set wayland,pulseaudio,gpu,session_bus
# Install firefox with apk
$ ./alpine.flatimage fim-root apk add firefox font-noto
# Test the application
$ ./alpine.flatimage fim-exec firefox
# Set the default startup command
$ ./alpine.flatimage fim-cmd firefox
# (optional) Compress the package filesystem
$ ./alpine.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv alpine.flatimage firefox
# Run the application (you can also click on it in your file manager)
$ ./firefox
Archlinux
# Set the maximum filesystem size (use du -sh ./arch.flatimage to see actual size)
$ ./arch.flatimage fim-resize 4G
# Install python-pipx
$ ./arch.flatimage fim-root fakechroot pacman -S python-pipx ffmpeg
# Install the pip application inside the image
export PIPX_HOME=/opt/pipx
export PIPX_BIN_DIR=/usr/local/bin
$ ./arch.flatimage fim-root fakechroot pipx install yt-dlp
# Test the application
$ ./arch.flatimage fim-exec yt-dlp -f "bestvideo+bestaudio" "https://www.youtube.com/watch?v=srnyVw-OR0g"
# Set the default startup command
$ ./arch.flatimage fim-cmd yt-dlp
# (optional) Compress the package filesystem
$ ./arch.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv arch.flatimage yt-dlp
# Use the application (download youtube video)
$ ./yt-dlp -f 'bestvideo+bestaudio' 'https://www.youtube.com/watch?v=srnyVw-OR0g'
Ubuntu
# Set the maximum filesystem size (use du -sh ./focal.flatimage to see actual size)
$ ./focal.flatimage fim-resize 4G
# Install python-pip
$ ./focal.flatimage fim-root apt install -y python3-pip ffmpeg
# Install the pip application inside the image
$ ./focal.flatimage fim-root pip3 install yt-dlp
# Test the application
$ ./focal.flatimage fim-exec yt-dlp -f "bestvideo+bestaudio" https://www.youtube.com/watch?v=srnyVw-OR0g
# Set the default startup command
$ ./focal.flatimage fim-cmd yt-dlp
# (optional) Compress the package filesystem
$ ./focal.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv focal.flatimage yt-dlp.flatimage
# Use the application (download youtube video)
$ ./yt-dlp.flatimage -f 'bestvideo+bestaudio' https://www.youtube.com/watch?v=srnyVw-OR0g
Archlinux
# Set the maximum filesystem size (use du -sh ./arch.flatimage to see actual size)
$ ./arch.flatimage fim-resize 4G
# Set the desired permissions (so vlc can play from inside the container)
$ ./arch.flatimage fim-perms-set x11,pulseaudio
# Install npm/nodejs into the image
$ ./arch.flatimage fim-root fakechroot pacman -S nodejs npm vlc
# Configure prefix to the root of the image
$ ./arch.flatimage fim-exec npm config set prefix -g '/usr/local/'
# Install the npm application inside the image
$ ./arch.flatimage fim-root fakechroot npm install -g webtorrent-cli
# Test the application
$ ./arch.flatimage fim-exec webtorrent "magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c" --vlc
# Set the default startup command
$ ./arch.flatimage fim-cmd webtorrent
# (optional) Compress the package filesystem
$ ./arch.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv arch.flatimage webtorrent
# Use the application (stream legal torrent video)
$ ./webtorrent "magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c" --vlc
Ubuntu
# Set the maximum filesystem size (use du -sh ./focal.flatimage to see actual size)
$ ./focal.flatimage fim-resize 4G
# Set the desired permissions (so vlc can play from inside the container)
$ ./focal.flatimage fim-perms-set x11,pulseaudio
# Install npm/nodejs into the image
$ ./focal.flatimage fim-root apt install -y curl
$ ./focal.flatimage fim-root curl -fsSL https://deb.nodesource.com/setup_19.x | bash -
$ ./focal.flatimage fim-root apt-get install -y nodejs mpv
# Configure prefix to the root of the image
$ ./focal.flatimage fim-root npm config set prefix -g /usr/local
# Install the npm application inside the image
$ ./focal.flatimage fim-root npm install -g webtorrent-cli
# Test the application
$ ./focal.flatimage fim-exec webtorrent magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c --mpv
# Set the default startup command
$ ./focal.flatimage fim-cmd webtorrent
# (optional) Compress the package filesystem
$ ./focal.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv focal.flatimage webtorrent.flatimage
# Use the application (stream legal torrent video)
$ ./webtorrent.flatimage magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c --mpv
Note that vlc/mpv was installed inside the image, it is required since the image has no access to the host filesystem/applications.
# Set the maximum filesystem size (use du -sh ./arch.flatimage to see actual size)
$ ./arch.flatimage fim-resize 4G
# Set the desired permissions (so vlc can play from inside the container)
$ ./arch.flatimage fim-perms-set x11,pulseaudio
# Enter the container as root
$ FIM_ROOT=1 ./arch.flatimage
# Install npm/nodejs into the image
(fim@arch) → fakechroot pacman -S nodejs npm vlc
# Configure prefix to the root of the image
(fim@arch) → npm config set prefix -g '/usr/local/'
# Install the npm application inside the image
(fim@arch) → fakechroot npm install -g webtorrent-cli
# Press CTRL+D or type exit to quit the container
# Enter the container as an unprivileged user
$ ./arch.flatimage
# Test the application
(fim@arch) → webtorrent "magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c" --vlc
# Press CTRL+D or type exit to quit the container
# Set the default startup command
$ ./arch.flatimage fim-cmd webtorrent
# (optional) Compress the package filesystem
$ ./arch.flatimage fim-compress
# (optional) Rename the binary to the main application name
$ mv arch.flatimage webtorrent
# Use the application (stream legal torrent video)
$ ./webtorrent "magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c" --vlc
# Set the maximum filesystem size (use du -sh ./arch.flatimage to see actual size)
$ ./arch.flatimage fim-resize 4G
# Fetch the application
$ git clone https://github.com/htop-dev/htop.git
# Install the required build dependencies
$ ./arch.flatimage fim-root fakechroot pacman -S ncurses automake autoconf gcc make
# Compile the application
cd htop
$ ../arch.flatimage fim-exec './autogen.sh'
$ ../arch.flatimage fim-exec './configure'
$ ../arch.flatimage fim-exec 'make'
# Run the compiled application
$ ./htop
# Set the maximum filesystem size (use du -sh ./arch.flatimage to see actual size)
$ ./arch.flatimage fim-resize 4G
# Fetch the application
$ git clone https://github.com/htop-dev/htop.git
# Enter the container as root
$ FIM_ROOT=1 ./arch.flatimage
# Install the required build dependencies
(fim@arch) → fakechroot pacman -S ncurses automake autoconf gcc make
# Compile
(fim@arch) → cd htop
(fim@arch) → ./autogen.sh
(fim@arch) → ./configure
(fim@arch) → make
# Run
(fim@arch) → ./htop
In this case arch.flatimage
is now a portable building environment for htop.
Creates a portable steam installation that works on both GNU
and MUSL
systems:
wget -O- https://raw.githubusercontent.com/ruanformigoni/flatimage/master/samples/steam.sh | sh
The home directory (where your games will be installed into) for this steam sample is always on the same directory as the flatimage, in a folder called steam.home
. This enables the usage of steam on an external hard drive that maybe plugged in several linux distros, without having to re-configure anything.
Creates a portable wine installation that works on both GNU
and MUSL
systems:
wget https://github.com/gameimage/runners/releases/download/wine-gnu-x86_64/base.flatimage.tar.xz
wget https://github.com/gameimage/runners/releases/download/wine-gnu-x86_64/staging.dwarfs
tar xf base.flatimage.tar.xz
rm base.flatimage.tar.xz
chmod +x base.flatimage
./base.flatimage fim-dwarfs-add staging.dwarfs /fim/mount/wine
rm staging.dwarfs
mv ./base.flatimage ./wine
You can use it simply by:
Currently to run a flatimage inside docker, the --privileged
flag is required.
Assuming that the current directory contains the image alpine.flatimage
:
docker run --privileged -it --rm -v "$(pwd):/workdir" ubuntu:focal /bin/bash
cd workdir
./alpine.flatimage
FlatImage offers on build simplicity, packaging applications should be as simple as installing them natively on the host system. This is an effort for the end-user to not depend on the application developer to provide the portable binary (or to handle how to package the application, dependencies and create a runner script). It also simplifies the quality of life of the package developer, simplifying the packaging process of applications.
-
The idea of this application sprung with the challenge to package software and dynamic libraries, such as
wine
, when there are hard-coded paths. The best solution is invasive https://github.com/AppImage/AppImageKit/wiki/Bundling-Windows-applications , which patches the binaries of wine directly to use a custom path for the 32-bit libraries (an implementation of this concept is available here), not only that, it requires to patch the32-bit
pre-loaderld-linux.so
as well, however, sometimes it still fails to execute properly. This is an over exceeding complexity for the end-user, which should package applications with no effort;FlatImage
changes the root filesystem the application runs in, to a minimal gnu subsystem, and with that, it solves the previous issues with dynamic libraries no workarounds required. No host libraries are used, which decreases issues of portable applications working on one machine and not in other. -
The fragmentation of the linux package management is considerable in modern times, e.g.,
apt
,pip
,npm
, and more. To mitigate this issueFlatImage
can perform the installation through the preferred package manager, and turn the program into an executable file, that can run in any linux distribution. E.g.: The user ofFlatImage
can create a binary ofyoutube-dl
, from thepip
package manager, without having either pip or python installed on the host operating system. -
Some applications are offered as pre-compiled compressed tar files (tarballs), which sometimes only work when installed on the root of the operating system. However, doing so could hinder the operating system integrity, to avoid this issue
FlatImage
can install tarballs into itself and turn them into a portable binary.