diff --git a/src-tauri/src/core/clash.rs b/src-tauri/src/core/clash.rs
index 6e200d03e856225331d5dd23d7c913971a11cbe2..a8699db793ba479d7a0fca3c0f332a2137891c14 100644
--- a/src-tauri/src/core/clash.rs
+++ b/src-tauri/src/core/clash.rs
@@ -258,8 +258,16 @@ impl Clash {
     config::save_yaml(temp_path.clone(), &config, Some("# Clash Verge Temp File"))?;
 
     tauri::async_runtime::spawn(async move {
+      // `external-controller` could be
+      // "127.0.0.1:9090" or ":9090"
+      // Todo: maybe it could support single port
       let server = info.server.unwrap();
-      let server = format!("http://{server}/configs");
+      let server = match server.starts_with(":") {
+        true => format!("http://127.0.0.1{server}/configs"),
+        false => format!("http://{server}/configs"),
+      };
+
+      dbg!(&server);
 
       let mut headers = HeaderMap::new();
       headers.insert("Content-Type", "application/json".parse().unwrap());
diff --git a/src/services/api.ts b/src/services/api.ts
index d5c96c39def8eb19dad7287ceb6a90599e389869..192a8a8156e66349a02bf3c23cdb9a306b07e278 100644
--- a/src/services/api.ts
+++ b/src/services/api.ts
@@ -14,7 +14,13 @@ export async function getAxios(force: boolean = false) {
   try {
     const info = await getClashInfo();
 
-    if (info?.server) server = info?.server;
+    if (info?.server) {
+      server = info.server;
+
+      // compatible width `external-controller`
+      if (server.startsWith(":")) server = `127.0.0.1${server}`;
+      else if (/^\d+$/.test(server)) server = `127.0.0.1:${server}`;
+    }
     if (info?.secret) secret = info?.secret;
   } catch {}