OpenMaui.AppImage 1.2.4

dotnet tool install --global OpenMaui.AppImage --version 1.2.4
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local OpenMaui.AppImage --version 1.2.4
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=OpenMaui.AppImage&version=1.2.4
                    
nuke :add-package OpenMaui.AppImage --version 1.2.4
                    

OpenMaui.AppImage

Package .NET MAUI Linux apps as universal AppImages, .deb and .rpm packages — one command from csproj to distributable.

NuGet NuGet Downloads License .NET GitHub

Developed by MarketAlly Pte Ltd

AI assistants / automation: follow docs/PACKAGING-GUIDE.md — a self-contained, copy-paste-exact reference (commands, options, recipes, verification, troubleshooting) intended to be consumed verbatim.

What is AppImage?

AppImage is a universal Linux package format that allows you to distribute applications as a single executable file that works on most Linux distributions without installation.

Features

  • One-command packaging with --project — the tool runs dotnet publish itself and packages the result
  • Package any .NET MAUI Linux app as an AppImage
  • .deb and .rpm output (--format deb|rpm|all) — installs to /opt/<app-id> with a /usr/bin launcher, desktop entry, hicolor icon and optional AppStream metainfo; host libraries become Depends/Requires/Recommends with per-distro package names. The .deb is written in managed code (no dpkg-deb, no root); the .rpm uses rpmbuild
  • Package a .deb or existing AppDir with --appdir — turn any FHS tree (Tauri, Electron, deb packages) into an AppImage, no linuxdeploy required
  • appimagetool auto-fetch — downloads and caches the official release when it isn't installed (--no-fetch to forbid network)
  • Works in CI / containers without FUSE — auto-detects a missing /dev/fuse and runs appimagetool in extract-and-run mode
  • Auto-detection of executable, icon, name, and version from your project
  • Host dependency intelligence — prints the native libraries the target machine needs (GStreamer, webkit2gtk, …), and --host-deps-check adds a friendly launch-time check to the AppImage
  • Self-updating AppImages (--update-info), GPG signing (--sign), and AppStream metainfo (--metainfo)
  • Automatic .desktop file generation with proper StartupWMClass for taskbar integration
  • Built-in installer dialog on first run
  • Install/Reinstall/Uninstall support
  • No root access required

Prerequisites

  1. .NET 10 SDK or later
  2. appimagetool — optional: when it isn't found on the host, the tool automatically downloads the official continuous release into ~/.cache/openmaui-appimage/ and reuses it on later runs. A clear notice with the download URL is printed on first download (the continuous tag publishes no reliable checksum). Pass --no-fetch to forbid network access and install it yourself:
# Download
wget https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage

# Make executable
chmod +x appimagetool-x86_64.AppImage

# Move to PATH
sudo mv appimagetool-x86_64.AppImage /usr/local/bin/appimagetool

Installation

dotnet tool install --global OpenMaui.AppImage

From source

git clone https://github.com/open-maui/appimage.git
cd appimage
dotnet build

Usage

Quick Start — one command

openmaui-appimage --project ./MyApp

That's it. The tool:

  1. Resolves the .csproj (a project directory or the file itself)
  2. Runs dotnet publish -c Release -r linux-x64 --self-contained true (RID matches the host; override with --rid)
  3. Derives --name from the csproj (AssemblyName or file name) and --app-version from its Version property
  4. Packages the publish output as <Name>.AppImage
  5. Prints a Host runtime dependencies report for the target machines

Manual flow (pre-published apps)

cd YourMauiApp
dotnet publish -c Release -r linux-x64 --self-contained

openmaui-appimage \
    --input bin/Release/net10.0/linux-x64/publish \
    --output YourApp.AppImage \
    --name "Your App"

Either way, the tool automatically detects:

  • Executable: Finds the main executable (ELF binary or .runtimeconfig.json)
  • Icon: Reads MauiIcon from your .csproj and composites background + foreground

Options

Option Short Required Description
--input -i Yes* Path to published .NET app directory (*or use --project)
--project -p Yes* Path to a .csproj (or a directory containing one); the tool publishes it itself. Mutually exclusive with --input.
--rid No RID for dotnet publish with --project (default: host arch, e.g. linux-x64)
--output -o With --input for AppImage/Flatpak Output file path (defaults to <Name>.AppImage, or the conventional .deb/.rpm file name). With several formats it is an output directory.
--name -n With --input Application name (derived from the csproj with --project)
--executable -e No Main executable name (auto-detected if not specified)
--icon No Path to icon (auto-detected from MauiIcon if not specified)
--category -c No Desktop category (default: Utility)
--app-version No App version (default: 1.0.0, or the csproj Version with --project)
--comment No App description
--app-id No Reverse-DNS application id (e.g. com.example.MyApp), used for Flatpak, --metainfo, and the .deb/.rpm install layout (default there: the csproj ApplicationId)
--format -f No appimage (default), flatpak, deb, rpm, all (= appimage + deb + rpm), or a comma-separated combination such as deb,rpm. See System packages.
--appdir No Treat --input as a pre-structured AppDir / FHS tree (e.g. a directory extracted from a .deb: usr/bin, usr/lib, usr/share) instead of a flat publish dir. See Packaging a .deb or existing AppDir.
--no-fuse No Always run appimagetool in extract-and-run mode instead of FUSE-mounting. FUSE is auto-detected by default; use this when FUSE is present but broken.
--no-fetch No Forbid network access: never auto-download appimagetool
--host-deps-check No Inject a launch-time host-library check into AppRun. See Host runtime dependencies.
--update-info No appimagetool update information (-u) for zsync self-updating AppImages. See Self-updating AppImages.
--sign No GPG-sign the AppImage (appimagetool --sign)
--sign-key No GPG key id to sign with (implies --sign)
--metainfo No Generate AppStream metainfo.xml. See AppStream metainfo.
--developer No Developer name for the AppStream metainfo (also the default .deb/.rpm maintainer name)
--package-name No .deb/.rpm package and launcher name (default: lowercased app name, e.g. shelldemo)
--maintainer No "Name <email>" for the .deb Maintainer / .rpm Packager (default: --developer, else csproj Authors)
--license No SPDX license for the .rpm (default: csproj PackageLicenseExpression, else LicenseRef-Proprietary)
--homepage No Homepage for .deb/.rpm (default: csproj PackageProjectUrl)
--release No Package release / Debian revision (default: 1)

Desktop Categories

Common categories: Utility, Development, Game, Graphics, Network, Office, AudioVideo, System

Running the AppImage

First Run - Installer Dialog

When you run an AppImage for the first time, a dialog appears:

  • Install: Copies to ~/.local/bin, creates menu entry and icon
  • Run Only: Runs the app without installing

Already Installed

If you run the AppImage again from a different location (e.g., Desktop), you'll see options:

  • Run the application: Just runs it
  • Reinstall (update): Updates the installed version
  • Uninstall: Removes the app from your system

From the Launcher

Once installed, clicking the app in your application menu runs it directly (no dialog).

Command Line Flags

# Run normally (shows dialog if not installed)
./YourApp.AppImage

# Force install dialog
./YourApp.AppImage --install

> Note (KDE Plasma): the very first install of a new app icon may show a
> generic icon in the launcher/taskbar until the next login — Plasma caches
> icon lookups in-memory and only rescans for brand-new icon names on shell
> restart. Launch feedback and subsequent updates are unaffected.

# Uninstall
./YourApp.AppImage --uninstall

# Show help
./YourApp.AppImage --help

Example: Packaging ShellDemo

# One command — publish + package
openmaui-appimage --project maui-linux-samples/ShellDemo

# Or the manual flow
cd maui-linux-samples/ShellDemo
dotnet publish -c Release -r linux-x64 --self-contained
openmaui-appimage \
    -i bin/Release/net10.0/linux-x64/publish \
    -o ShellDemo.AppImage \
    -n "Shell Demo"

Host runtime dependencies

AppImages bundle your app but not the host's system libraries. After packaging, the tool scans the publish tree for OpenMaui feature assemblies and prints a concise Host runtime dependencies report — what the target machine needs:

  • OpenMaui.Controls.Linux.dll → required base set: libX11, libwayland-client, fontconfig, GTK 3 (gtk_init_check runs at startup); plus optional, feature-gated libraries: libcups (printing), libayatana-appindicator3/libappindicator3 (tray icon), WPE WebKit 2.54+ (WebView, native mode), webkit2gtk-4.1 (WebView, GTK-mode fallback)
  • OpenMaui.Controls.Linux.Blazor.dll → makes WPE WebKit 2.54+ required
  • OpenMaui.Controls.Linux.MediaElement.dll → GStreamer 1.x + base/good plugins
  • OpenMaui.Controls.Linux.Maps.dll → nothing native (network access only)

Each entry lists the Fedora (dnf) and Debian/Ubuntu (apt) package names.

WPE WebKit 2.54+ availability: Fedora ships none, it comes from the philn/wpewebkit COPR (sudo dnf copr enable philn/wpewebkit && sudo dnf install wpewebkit). Debian testing/sid: sudo apt install libwpewebkit-2.0-1. Debian 13 and Ubuntu have no 2.54 package: the WebView falls back to WebKitGTK in GTK mode (options.UseGtk = true) and BlazorWebView is unavailable there unless WPE 2.54 is built or installed from elsewhere.

--host-deps-check — launch-time check

Pass --host-deps-check to inject a small, dependency-free POSIX-sh block into the generated AppRun. At launch it probes the needed sonames via ldconfig -p:

  • Required base set missing → shows a friendly message (zenity or kdialog when available, stderr otherwise) listing the exact dnf/apt install commands, then aborts
  • Optional feature libraries missing → prints a note to stderr and continues (the corresponding features are simply unavailable)
openmaui-appimage --project ./MyApp --host-deps-check

System packages (.deb and .rpm)

openmaui-appimage --project ./MyApp -f deb           # myapp_<ver>-1_amd64.deb
openmaui-appimage --project ./MyApp -f rpm           # myapp-<ver>-1.x86_64.rpm
openmaui-appimage --project ./MyApp -f all -o dist/  # AppImage + .deb + .rpm into dist/

The same publish output, metadata and dependency scan feed every format. Layout on the target:

Path Content
/opt/<app-id>/ the self-contained publish output
/usr/bin/<package-name> launcher script (exec /opt/<app-id>/<exe> "$@")
/usr/share/applications/<app-id>.desktop desktop entry (Icon=<app-id>, StartupWMClass)
/usr/share/icons/hicolor/{scalable,<n>x<n>}/apps/<app-id>.{svg,png} icon (SVG to scalable, PNG to its own size)
/usr/share/metainfo/<app-id>.metainfo.xml with --metainfo

Files are owned by root:root, directories and executables are 0755, everything else (including .so libraries) 0644. No maintainer scripts: desktop-database and icon-cache refreshes come from the distros' own triggers.

Dependencies. The .NET runtime prerequisites (glibc, libstdc++, zlib, OpenSSL, ICU) and the scanner's required libraries become Depends: (deb) / Requires: (rpm); feature-gated libraries become Recommends:. WPE WebKit is only ever a version-qualified Recommends (libwpewebkit-2.0-1 (>= 2.54), wpewebkit >= 2.54), even for BlazorWebView apps, so the package installs on stock Fedora, Debian 13 and Ubuntu; the packaging output and the rpm description carry the install notes. The rpm sets AutoReqProv: no so the bundled .so files are not exported as system-wide provides, and disables stripping/debuginfo so the .NET payload is shipped untouched.

Tooling. The .deb is written in managed code (ar + control.tar.gz + data.tar.gz with md5sums), so it builds on any distro without dpkg-deb or root. The .rpm needs rpmbuild (run with a private _topdir, nothing lands in ~/rpmbuild): sudo dnf install rpm-build on Fedora, sudo apt install rpm on Debian/Ubuntu. --appdir is AppImage-only.

Self-updating AppImages (zsync)

Pass --update-info to embed update information (appimagetool -u), producing a .zsync file next to the AppImage. Tools like AppImageUpdate can then update the app by downloading only the changed blocks. The common shape for GitHub releases is:

openmaui-appimage --project ./MyApp \
    --update-info "gh-releases-zsync|myuser|myrepo|latest|MyApp-*.AppImage.zsync"

Upload both the produced .AppImage and .zsync files to your release.

Signing

# Sign with your default GPG key
openmaui-appimage --project ./MyApp --sign

# Sign with a specific key (implies --sign)
openmaui-appimage --project ./MyApp --sign-key ABCDEF1234567890

These are passed straight through to appimagetool (--sign / --sign-key), which embeds a GPG signature into the AppImage.

AppStream metainfo

--metainfo generates a minimal, valid AppStream file at AppDir/usr/share/metainfo/<app-id>.metainfo.xml (component type="desktop-application", with launchable, provides/binary, and the summary from --comment), which app stores and software centers read:

openmaui-appimage --project ./MyApp --metainfo \
    --app-id com.example.MyApp \
    --comment "A great app" \
    --developer "Example Inc."

The --app-id should be reverse-DNS (com.example.MyApp); the tool warns when it isn't, and derives a com.openmaui.* fallback id when the option is omitted.

Packaging a .deb or existing AppDir

By default the tool expects a flat publish directory and copies it into AppDir/usr/bin. That's perfect for dotnet publish output, but some apps — Tauri, Electron, anything you already have as a .deb — are laid out as an FHS tree (usr/bin, usr/lib, usr/share). Pass --appdir to package one of those directly: the tree is used as the AppDir root (so resources under usr/lib / usr/share are preserved) and the executable is resolved under usr/bin.

This turns the tool into a .deb → AppImage converter — useful for shipping an AppImage from a bundler that only emits a .deb, without pulling in linuxdeploy:

# Extract the .deb into an AppDir tree
dpkg-deb -x YourApp_1.0.0_amd64.deb appdir

# Package it (executable auto-detected under usr/bin, or pass --executable)
openmaui-appimage \
    --appdir \
    -i appdir \
    -o YourApp.AppImage \
    -n "Your App" \
    --executable your-app \
    --icon path/to/icon.svg

Note: like any AppImage, this bundles your app but not the host's shared GUI libraries (GTK/WebKit/etc.). A self-contained app (or one whose deb already vendors its libs) is fully portable; otherwise the target needs those system libraries — the same dependency the .deb declares.

How It Works

  1. AppDir Structure: Creates the standard AppImage directory structure:

    YourApp.AppDir/
    ├── AppRun              # Entry point script
    ├── YourApp.desktop     # Desktop integration
    ├── YourApp.svg         # Application icon
    └── usr/
        ├── bin/            # Your published .NET app
        │   └── appicon.svg # Runtime icon for window
        └── share/icons/    # XDG icon directories
    
  2. AppRun Script: A bash script that:

    • Sets up the environment (PATH, LD_LIBRARY_PATH)
    • Shows installer dialog on first run
    • Handles --install, --uninstall, and --help flags
    • Launches the .NET application
  3. Desktop Integration:

    • Creates .desktop file with StartupWMClass for proper taskbar icon matching
    • Installs icon to XDG icon directories
    • Updates icon cache automatically
  4. appimagetool: Packages everything into a single executable AppImage file

Self-Contained vs Framework-Dependent

dotnet publish -c Release -r linux-x64 --self-contained
  • Works on any Linux system without .NET installed
  • Larger AppImage size

Framework-Dependent (smaller size)

dotnet publish -c Release -r linux-x64 --self-contained false
  • Smaller AppImage (~50-100MB smaller)
  • Requires .NET runtime on target system

Troubleshooting

"appimagetool not found"

By default the tool downloads appimagetool automatically (cached in ~/.cache/openmaui-appimage/). If you passed --no-fetch or the download failed, install it as described in Prerequisites.

"Could not find executable"

The auto-detection looks for:

  1. ELF binaries (self-contained apps)
  2. .runtimeconfig.json files (framework-dependent apps)

If it fails, use --executable to specify the correct name (without extension).

AppImage won't run

  1. Ensure it's executable: chmod +x YourApp.AppImage
  2. Check for missing dependencies: ./YourApp.AppImage (errors will be shown)

Taskbar icon not showing

The app sets WM_CLASS and the .desktop file includes StartupWMClass for proper matching. If issues persist:

  1. Reinstall the app to update the .desktop file
  2. Log out and back in to refresh the desktop environment

FUSE errors

Build time (this tool): handled automatically. appimagetool is itself an AppImage and needs FUSE to run, which is missing on many CI runners and LXC containers. The tool probes /dev/fuse and, when it's unavailable, sets APPIMAGE_EXTRACT_AND_RUN=1 so appimagetool extracts-and-runs instead of mounting — so packaging works in containers/CI with no extra flags. (It sets the env var rather than passing --appimage-extract-and-run, so a distro-packaged native appimagetool also works.) If FUSE is present but broken (auto-detect would try to mount and fail), pass --no-fuse to force extract-and-run.

Run time (the produced AppImage): the end user's machine still needs FUSE to mount the AppImage. Install it, or run extracted:

sudo apt install fuse libfuse2  # Debian/Ubuntu
sudo dnf install fuse fuse-libs  # Fedora

# or, no FUSE needed:
./YourApp.AppImage --appimage-extract-and-run

Development

# Build the solution
dotnet build

# Run the tests
dotnet test

The CLI lives in src/OpenMaui.AppImage (Program.cs is the entry point, Commands/ holds the command definition, Core/ the packaging logic), with unit tests in tests/OpenMaui.AppImage.Tests.

License

MIT License - see LICENSE

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.2.4 0 9/27/2026
1.2.3 87 9/20/2026
1.2.2 82 9/20/2026