diff --git a/app/Actions/Site/UpdateEnv.php b/app/Actions/Site/UpdateEnv.php
index ed8c0786..c221e4de 100644
--- a/app/Actions/Site/UpdateEnv.php
+++ b/app/Actions/Site/UpdateEnv.php
@@ -2,10 +2,14 @@
 
 namespace App\Actions\Site;
 
+use App\Exceptions\SSHUploadFailed;
 use App\Models\Site;
 
 class UpdateEnv
 {
+    /**
+     * @throws SSHUploadFailed
+     */
     public function update(Site $site, array $input): void
     {
         $site->server->os()->editFile(
diff --git a/app/Exceptions/SSHUploadFailed.php b/app/Exceptions/SSHUploadFailed.php
new file mode 100755
index 00000000..c2e67949
--- /dev/null
+++ b/app/Exceptions/SSHUploadFailed.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace App\Exceptions;
+
+class SSHUploadFailed extends SSHError
+{
+    //
+}
diff --git a/app/Facades/SSH.php b/app/Facades/SSH.php
index b98e7703..74c0eaa3 100644
--- a/app/Facades/SSH.php
+++ b/app/Facades/SSH.php
@@ -16,6 +16,8 @@
  * @method static string exec(string $command, string $log = '', int $siteId = null, ?bool $stream = false)
  * @method static string assertExecuted(array|string $commands)
  * @method static string assertExecutedContains(string $command)
+ * @method static string assertFileUploaded(string $toPath, ?string $content = null)
+ * @method static string getUploadedLocalPath()
  * @method static disconnect()
  */
 class SSH extends FacadeAlias
diff --git a/app/Http/Controllers/ApplicationController.php b/app/Http/Controllers/ApplicationController.php
index 91548601..e6b22f33 100644
--- a/app/Http/Controllers/ApplicationController.php
+++ b/app/Http/Controllers/ApplicationController.php
@@ -10,6 +10,7 @@
 use App\Exceptions\RepositoryNotFound;
 use App\Exceptions\RepositoryPermissionDenied;
 use App\Exceptions\SourceControlIsNotConnected;
+use App\Exceptions\SSHUploadFailed;
 use App\Facades\Toast;
 use App\Helpers\HtmxResponse;
 use App\Models\Deployment;
@@ -81,9 +82,12 @@ public function updateEnv(Server $server, Site $site, Request $request): Redirec
     {
         $this->authorize('manage', $server);
 
-        app(UpdateEnv::class)->update($site, $request->input());
-
-        Toast::success('Env updated!');
+        try {
+            app(UpdateEnv::class)->update($site, $request->input());
+            Toast::success('Env updated!');
+        } catch (SSHUploadFailed) {
+            Toast::error('Failed to update .env file!');
+        }
 
         return back();
     }
diff --git a/app/SSH/OS/OS.php b/app/SSH/OS/OS.php
index 1b346222..8d02583d 100644
--- a/app/SSH/OS/OS.php
+++ b/app/SSH/OS/OS.php
@@ -2,9 +2,14 @@
 
 namespace App\SSH\OS;
 
+use App\Exceptions\SSHUploadFailed;
 use App\Models\Server;
 use App\Models\ServerLog;
 use App\SSH\HasScripts;
+use Illuminate\Filesystem\FilesystemAdapter;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Str;
+use Throwable;
 
 class OS
 {
@@ -109,14 +114,25 @@ public function reboot(): void
         );
     }
 
+    /**
+     * @throws SSHUploadFailed
+     */
     public function editFile(string $path, ?string $content = null): void
     {
-        $this->server->ssh()->exec(
-            $this->getScript('edit-file.sh', [
-                'path' => $path,
-                'content' => $content ?? '',
-            ]),
-        );
+        $tmpName = Str::random(10).strtotime('now');
+        try {
+            /** @var FilesystemAdapter $storageDisk */
+            $storageDisk = Storage::disk('local');
+            $storageDisk->put($tmpName, $content);
+            $this->server->ssh()->upload(
+                $storageDisk->path($tmpName),
+                $path
+            );
+        } catch (Throwable) {
+            throw new SSHUploadFailed();
+        } finally {
+            $this->deleteTempFile($tmpName);
+        }
     }
 
     public function readFile(string $path): string
@@ -200,4 +216,11 @@ public function resourceInfo(): array
             'disk_free' => str($info)->after('disk_free:')->before(PHP_EOL)->toString(),
         ];
     }
+
+    private function deleteTempFile(string $name): void
+    {
+        if (Storage::disk('local')->exists($name)) {
+            Storage::disk('local')->delete($name);
+        }
+    }
 }
diff --git a/app/SSH/OS/scripts/edit-file.sh b/app/SSH/OS/scripts/edit-file.sh
deleted file mode 100644
index 67e5def6..00000000
--- a/app/SSH/OS/scripts/edit-file.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-if ! echo "__content__" | tee __path__; then
-    echo 'VITO_SSH_ERROR' && exit 1
-fi
diff --git a/app/Support/Testing/SSHFake.php b/app/Support/Testing/SSHFake.php
index 2cecde99..2551462d 100644
--- a/app/Support/Testing/SSHFake.php
+++ b/app/Support/Testing/SSHFake.php
@@ -17,6 +17,12 @@ class SSHFake extends SSH
 
     protected bool $connectionWillFail = false;
 
+    protected string $uploadedLocalPath;
+
+    protected string $uploadedRemotePath;
+
+    protected string $uploadedContent;
+
     public function __construct(?string $output = null)
     {
         $this->output = $output;
@@ -63,6 +69,9 @@ public function exec(string $command, string $log = '', ?int $siteId = null, ?bo
 
     public function upload(string $local, string $remote): void
     {
+        $this->uploadedLocalPath = $local;
+        $this->uploadedRemotePath = $remote;
+        $this->uploadedContent = file_get_contents($local);
         $this->log = null;
     }
 
@@ -105,4 +114,22 @@ public function assertExecutedContains(string $command): void
         }
         Assert::assertTrue(true, $executed);
     }
+
+    public function assertFileUploaded(string $toPath, ?string $content = null): void
+    {
+        if (! $this->uploadedLocalPath || ! $this->uploadedRemotePath) {
+            Assert::fail('File is not uploaded');
+        }
+
+        Assert::assertEquals($toPath, $this->uploadedRemotePath);
+
+        if ($content) {
+            Assert::assertEquals($content, $this->uploadedContent);
+        }
+    }
+
+    public function getUploadedLocalPath(): string
+    {
+        return $this->uploadedLocalPath;
+    }
 }
diff --git a/tests/Feature/ApplicationTest.php b/tests/Feature/ApplicationTest.php
index b1e120a7..4cf62c4f 100644
--- a/tests/Feature/ApplicationTest.php
+++ b/tests/Feature/ApplicationTest.php
@@ -179,10 +179,10 @@ public function test_update_env_file(): void
             'server' => $this->server,
             'site' => $this->site,
         ]), [
-            'env' => 'APP_ENV=production',
+            'env' => 'APP_ENV="production"',
         ])->assertSessionDoesntHaveErrors();
 
-        SSH::assertExecutedContains('echo "APP_ENV=production" | tee /home/vito/'.$this->site->domain.'/.env');
+        SSH::assertFileUploaded('/home/vito/'.$this->site->domain.'/.env', 'APP_ENV="production"');
     }
 
     public function test_git_hook_deployment(): void