diff --git a/amadeus/src/main.rs b/amadeus/src/main.rs
index ffb31bf782e5561e8fb88324b31de78eb455e513..d5ff63038bf992f27d1ed9d0cdec24d6491f05b8 100644
--- a/amadeus/src/main.rs
+++ b/amadeus/src/main.rs
@@ -42,29 +42,41 @@ use style_sheet::sizes::SIZE_FONT_NORMAL;
 
 fn main() -> Result<()> {
     logger::init(Some(log::Level::Debug)).expect("failed to install logger");
+    #[cfg(target_os = "linux")]
+    appimage::detect_appimage()?;
+
     let config = config::get_or_write_default_config::<AmadeusConfig>("amadeus")
         .with_context(|| "failed to read or write the config file")?;
     logger::level(config.log);
-    Ok(<Amadeus as iced::Application>::run(iced::Settings {
+
+    let settings = iced::Settings {
         id: Some("Amadeus".to_string()),
+        flags: config,
+        default_font: iced::font::Font::DEFAULT,
+        default_text_size: SIZE_FONT_NORMAL.into(),
+        antialiasing: false,
+        exit_on_close_request: false,
+
         window: iced::window::Settings {
             icon: Some(iced::window::icon::from_file_data(
                 include_bytes!("../amadeus.png"),
                 Some(image::ImageFormat::Png),
             )?),
+
             resizable: true,
-            decorations: true, // Wait for https://github.com/iced-rs/iced/pull/1542 to be merged
             transparent: false,
             visible: true,
             min_size: Some((900, 600)),
             level: iced::window::Level::AlwaysOnTop,
             position: iced::window::Position::Centered,
+
+            // Wait for https://github.com/iced-rs/iced/pull/1542 to be merged
+            decorations: true,
+
             ..Default::default()
         },
-        flags: config,
-        default_font: iced::font::Font::DEFAULT,
-        default_text_size: SIZE_FONT_NORMAL.into(),
-        antialiasing: false,
-        exit_on_close_request: false,
-    })?)
+    };
+
+    <Amadeus as iced::Application>::run(settings)?;
+    Ok(())
 }
diff --git a/lektor_utils/src/appimage.rs b/lektor_utils/src/appimage.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9acea0fec8db7772521e5bbda85dd519f6f43041
--- /dev/null
+++ b/lektor_utils/src/appimage.rs
@@ -0,0 +1,32 @@
+//! AppImage detection, log and change directories accordingly. Available only on Linux.
+
+use anyhow::{bail, Context, Result};
+
+/// Detect AppImage runtime throu env variables and change directory to the one where the AppImage
+/// was called from. We log everything for debuging purpose. Available only in Linux.
+/// ```
+/// #[cfg(target_os = "linux")]
+/// appimage::detect_appimage()?;
+/// ```
+pub fn detect_appimage() -> Result<()> {
+    match (
+        std::env::var_os("APPIMAGE"),
+        std::env::var_os("APPDIR"),
+        std::env::var_os("OWD"),
+        std::env::var_os("ARGV0"),
+    ) {
+        (Some(appimage), Some(mountpoint), Some(cwd), Some(name)) => {
+            let (appimage, mountpoint, owd, name) = (
+                appimage.to_str().unwrap_or("..."),
+                mountpoint.to_str().unwrap_or("..."),
+                cwd.to_str().unwrap_or("..."),
+                name.to_str().unwrap_or("..."),
+            );
+            log::info!("runing as an AppImage\n- appimage: {appimage}\n- launched as: {name}\n- mountpoint: {mountpoint}\n- working dir: {owd}");
+            std::env::set_current_dir(&cwd).with_context(|| "failed to go to the folder where the AppImage was launched from")?;
+        }
+        (None, None, None, None) => log::info!("runing with no AppImage runtime"),
+        invalid => bail!("invalid AppImage runtime V2 env variables, should get none or all, got partial: {invalid:?}"),
+    }
+    Ok(())
+}
diff --git a/lektor_utils/src/lib.rs b/lektor_utils/src/lib.rs
index abfd8fbb223c7e7986bbd2eae9a459d89fd9679e..0f98c69861f423628dbe247036f60b61dcfe4b44 100644
--- a/lektor_utils/src/lib.rs
+++ b/lektor_utils/src/lib.rs
@@ -19,6 +19,9 @@ mod macros;
 ))]
 pub mod is;
 
+#[cfg(target_os = "linux")]
+pub mod appimage;
+
 /// Pathdiff to handle some errors with WSL...
 pub mod pathdiff;
 
diff --git a/lektord/src/main.rs b/lektord/src/main.rs
index c3edf9d7c775ba765e3864fecb6554fcbe08f3ae..bad93de720ed4655c010a2ea8f1fde038983b17e 100644
--- a/lektord/src/main.rs
+++ b/lektord/src/main.rs
@@ -15,6 +15,9 @@ use tokio::{signal, sync::oneshot::Receiver};
 
 fn main() -> Result<()> {
     logger::init(Some(log::Level::Debug)).expect("failed to install logger");
+    #[cfg(target_os = "linux")]
+    appimage::detect_appimage()?;
+
     let config = lektor_utils::config::get_or_write_default_config::<LektorConfig>("lektord")?;
     let args = <cmd::Args as clap::Parser>::parse();
     lektor_utils::logger::level(config.log);
diff --git a/lkt/src/main.rs b/lkt/src/main.rs
index 1742cf7469341a71f138457ebb1cfe66d8b49c39..0f244fe5ea097b5e12150b665f187dcb1e4068cf 100644
--- a/lkt/src/main.rs
+++ b/lkt/src/main.rs
@@ -15,6 +15,9 @@ use std::{borrow::Cow, ops::RangeBounds};
 
 fn main() -> Result<()> {
     logger::init(Some(log::Level::Trace)).expect("failed to install logger");
+    #[cfg(target_os = "linux")]
+    appimage::detect_appimage()?;
+
     let args = <args::Args as clap::Parser>::parse();
     let manpage = matches!(args.action, SubCommand::Admin { manpage: true, .. });
     let shell = match args.action {