coollabsio/coolify · error · Exception

Failed to create SSH keys storage directory

Error message

Failed to create SSH keys storage directory

What it means

Thrown by PrivateKey::ensureStorageDirectoryExists() (app/Models/PrivateKey.php:276), called at the top of storeInFileSystem(). If the 'ssh-keys' disk root does not exist, it attempts $disk->makeDirectory('') and treats a false return as a hard failure. In practice the storage root is the configured disk root (e.g. /data/coolify/ssh inside the container), and makeDirectory fails when the parent path is not writable by the Coolify process — so the directory cannot be (re)created.

Source

Thrown at app/Models/PrivateKey.php:276

    public static function deleteFromStorage(self $privateKey)
    {
        $filename = "ssh_key@{$privateKey->uuid}";
        $disk = Storage::disk('ssh-keys');

        if ($disk->exists($filename)) {
            $disk->delete($filename);
        }
    }

    protected function ensureStorageDirectoryExists()
    {
        $disk = Storage::disk('ssh-keys');
        $directoryPath = '';

        if (! $disk->exists($directoryPath)) {
            $success = $disk->makeDirectory($directoryPath);
            if (! $success) {
                throw new \Exception('Failed to create SSH keys storage directory');
            }
        }

        // Check if directory is writable by attempting a test file
        $testFilename = '.test_write_'.uniqid();
        $testSuccess = $disk->put($testFilename, 'test');

        if (! $testSuccess) {
            throw new \Exception('SSH keys storage directory is not writable. Run on the host: sudo chown -R 9999 /data/coolify/ssh && sudo chmod -R 700 /data/coolify/ssh && docker restart coolify');
        }

        // Clean up test file
        $disk->delete($testFilename);
    }

    public function getKeyLocation()
    {
        return Storage::disk('ssh-keys')->path("ssh_key@{$this->uuid}");

View on GitHub (pinned to 70b9acc424)

Solutions

  1. On the host: sudo chown -R 9999 /data/coolify/ssh && sudo chmod -R 700 /data/coolify/ssh && docker restart coolify (create the dir first if the parent lacks it: sudo mkdir -p /data/coolify/ssh).
  2. Verify the 'ssh-keys' disk root in config/filesystems.php points at the intended path.
  3. Retry the key save; ensureStorageDirectoryExists() will pass once the root exists and is writable.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: ensure the ssh-keys root exists and is creatable/writable
$root = Storage::disk('ssh-keys')->path('');
if (! is_dir($root) && ! @mkdir($root, 0700, true)) {
    throw new \RuntimeException("Cannot create SSH storage root: {$root}");
}
if (! is_writable($root)) {
    throw new \RuntimeException("SSH storage root not writable: {$root}");
}

Try / catch

try {
    $privateKey->storeInFileSystem();
} catch (\Exception $e) {
    if (str_contains($e->getMessage(), 'Failed to create SSH keys storage directory')) {
        // create+chown the root on the host: mkdir -p /data/coolify/ssh && chown -R 9999 … && docker restart coolify
    }
    throw $e;
}

Prevention

When it happens

Trigger: First key save after install when /data/coolify (the parent) is root-owned and /data/coolify/ssh does not yet exist; the ssh dir was deleted while the container was running; a misconfigured 'ssh-keys' disk root pointing somewhere unwritable.

Common situations: Fresh self-hosted installs with wrong volume ownership; operators deleting /data/coolify/ssh to 'reset'; custom filesystems.php config with a bad root path.

Related errors


AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17). Data as JSON: /api/errors/7598e4338b8ed81a. Report an issue: GitHub.