coollabsio/coolify · error · Exception

Failed to open lock file for SSH key: {$lockFile}

Error message

Failed to open lock file for SSH key: {$lockFile}

What it means

Thrown by PrivateKey::storeInFileSystem() (app/Models/PrivateKey.php:217). Before writing ssh_key@{uuid}, the routine opens a sibling lock file ({keyLocation}.lock) with fopen($lockFile, 'c') to serialize concurrent writes. ensureStorageDirectoryExists() has already run at this point, so a false return means the OS refused to create/open the lock file itself — almost always a permission or path-level denial on the 'ssh-keys' disk (root /data/coolify/ssh), e.g. open_basedir restrictions, SELinux denial, or a read-only mount.

Source

Thrown at app/Models/PrivateKey.php:217

            'isValid' => $isValid,
            'publicKey' => $publicKey,
        ];
    }

    public function storeInFileSystem()
    {
        $filename = "ssh_key@{$this->uuid}";
        $disk = Storage::disk('ssh-keys');
        $keyLocation = $this->getKeyLocation();
        $lockFile = $keyLocation.'.lock';

        // Ensure the storage directory exists and is writable
        $this->ensureStorageDirectoryExists();

        // Use file locking to prevent concurrent writes from corrupting the key
        $lockHandle = fopen($lockFile, 'c');
        if ($lockHandle === false) {
            throw new \Exception("Failed to open lock file for SSH key: {$lockFile}");
        }

        try {
            if (! flock($lockHandle, LOCK_EX)) {
                throw new \Exception("Failed to acquire lock for SSH key: {$keyLocation}");
            }

            // Attempt to store the private key
            $success = $disk->put($filename, $this->private_key);

            if (! $success) {
                throw new \Exception("Failed to write SSH key to filesystem. Check disk space and permissions for: {$keyLocation}");
            }

            // Verify the file was actually created and has content
            if (! $disk->exists($filename)) {
                throw new \Exception("SSH key file was not created: {$keyLocation}");
            }

View on GitHub (pinned to 70b9acc424)

Solutions

  1. On the host run: sudo chown -R 9999 /data/coolify/ssh && sudo chmod -R 700 /data/coolify/ssh && docker restart coolify.
  2. Confirm the mount is writable: docker exec coolify touch /data/coolify/ssh/.wtest.
  3. Check open_basedir/SELinux denials in PHP-FPM and host audit logs if ownership looks correct.
  4. Retry the key save once write access is confirmed.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: can the process create a file next to the key location?
$dir = dirname($privateKey->getKeyLocation());
if (! is_dir($dir) || ! is_writable($dir)) {
    throw new \RuntimeException("SSH storage dir not writable: {$dir}");
}

Try / catch

try {
    $privateKey->storeInFileSystem();
} catch (\Exception $e) {
    if (str_contains($e->getMessage(), 'Failed to open lock file')) {
        // ownership/open_basedir problem on /data/coolify/ssh — fix and retry
    }
    throw $e;
}

Prevention

When it happens

Trigger: Saving/creating/updating a PrivateKey while the Coolify process (uid 9999) cannot create files in the ssh-keys storage root — directory exists but is owned by root with no write bit, is mounted read-only, or PHP open_basedir excludes the path.

Common situations: Host permission drift on /data/coolify/ssh after host OS upgrades or restores; hardened PHP configs with open_basedir; containers started with a :ro bind mount for the data volume.

Related errors


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