Version: 2.64.1 (Docker image marcpope/borgbackupserver:latest)
Summary
Creating a "local" repository via POST /api/v1/clients/{id}/repositories (and, as far as I can tell, the equivalent web UI flow) fails borg init in two ways, because the init step runs on the server itself but is built as if it were running on the agent.
Bug 1: hardcoded SSH port 22, ignoring the configured ssh_port setting
AdminApiController::createRepository() runs borg init synchronously on the server:
src/Controllers/Api/AdminApiController.php:434
$env = BorgCommandBuilder::buildEnv($repo);
buildEnv() is called with no $sshPort argument, so it falls back to the hardcoded default:
src/Services/BorgCommandBuilder.php:204-205
$port = $sshPort ?? 22;
$env['BORG_RSH'] = "ssh -i /etc/bbs-agent/ssh_key -p {$port} ...";
This ignores the ssh_port value stored in settings (used correctly elsewhere for actual agent backup/restore tasks). If the server's SSH port has been changed from the default 22 (e.g. SSH_PORT=2222 in the Docker Compose env, which is the value the README's Quick Start / docker-compose.yml itself uses), repo creation fails immediately with:
Remote: ssh: connect to host <server-ip> port 22: Connection refused
Fix: read the ssh_port setting and pass it into buildEnv($repo, ..., $sshPort) in createRepository() (and any other server-side call sites that build an init/access command for a "local" repo).
Bug 2: server-side init uses the agent's SSH identity file, which doesn't exist on the server
Even after working around Bug 1 (by also publishing container port 22), borg init still fails, because buildEnv() defaults to $forAgent = true:
src/Services/BorgCommandBuilder.php:180
public static function buildEnv(array $repo, bool $forAgent = true, ?int $sshPort = null, ?array $remoteSshConfig = null): array
For an SSH-style repo path this branch sets BORG_RSH to use /etc/bbs-agent/ssh_key:
src/Services/BorgCommandBuilder.php:205
$env['BORG_RSH'] = "ssh -i /etc/bbs-agent/ssh_key -p {$port} ...";
That path is the agent's installed private key, present on client machines — it does not exist inside the bbs server container, where createRepository() actually executes (proc_open($initCmd, ..., $env) runs in-process on the server via Apache/PHP). The result:
Remote: Warning: Identity file /etc/bbs-agent/ssh_key not accessible: No such file or directory.
Remote: bbs-coolify@<server-ip>: Permission denied (publickey).
Fix: the self-init call in createRepository() should call buildEnv($repo, forAgent: false) (server-side local access, which the code already supports and uses correctly elsewhere — see the else branch a few lines down that sets BORG_BASE_DIR/HOME for www-data), or borg init should operate directly on the local filesystem path (BorgCommandBuilder::getLocalRepoPath(), which the surrounding code already computes for the create-repo-dir helper call a few lines earlier) instead of round-tripping through the repo's ssh:// path.
Workaround (for anyone hitting this)
- Publish the container's SSH port on the host as both the configured
SSH_PORT and plain 22 (e.g. add "22:22" alongside "${SSH_PORT:-2222}:22" in docker-compose.yml), or revert SSH_PORT to 22.
- If
borg init still fails on the identity file, run it manually inside the container as www-data with BORG_BASE_DIR/HOME pointed at a writable cache dir, directly against the local repo path (/var/bbs/home/<agent_id>/<repo_name>) instead of the ssh:// path.
- After a manual init,
chown the repo directory (recursively) to the agent's SSH unix user (ssh_unix_user column in agents, e.g. bbs-agent-<n>) rather than www-data — otherwise the agent-side backup job fails separately with Failed to create/acquire the lock ... Permission denied, since normal backup/restore traffic connects as that unix user, not www-data.
Steps to reproduce
- Deploy via the official
docker-compose.yml, with SSH_PORT set to anything other than 22 (the compose file's own default is 2222).
- Register an agent, then create a local repository for it via the API or UI.
- Observe
borg init failing as above.
Version: 2.64.1 (Docker image
marcpope/borgbackupserver:latest)Summary
Creating a "local" repository via
POST /api/v1/clients/{id}/repositories(and, as far as I can tell, the equivalent web UI flow) failsborg initin two ways, because the init step runs on the server itself but is built as if it were running on the agent.Bug 1: hardcoded SSH port 22, ignoring the configured
ssh_portsettingAdminApiController::createRepository()runsborg initsynchronously on the server:buildEnv()is called with no$sshPortargument, so it falls back to the hardcoded default:This ignores the
ssh_portvalue stored insettings(used correctly elsewhere for actual agent backup/restore tasks). If the server's SSH port has been changed from the default 22 (e.g.SSH_PORT=2222in the Docker Compose env, which is the value the README's Quick Start / docker-compose.yml itself uses), repo creation fails immediately with:Fix: read the
ssh_portsetting and pass it intobuildEnv($repo, ..., $sshPort)increateRepository()(and any other server-side call sites that build an init/access command for a "local" repo).Bug 2: server-side init uses the agent's SSH identity file, which doesn't exist on the server
Even after working around Bug 1 (by also publishing container port 22),
borg initstill fails, becausebuildEnv()defaults to$forAgent = true:For an SSH-style repo path this branch sets
BORG_RSHto use/etc/bbs-agent/ssh_key:That path is the agent's installed private key, present on client machines — it does not exist inside the
bbsserver container, wherecreateRepository()actually executes (proc_open($initCmd, ..., $env)runs in-process on the server via Apache/PHP). The result:Fix: the self-init call in
createRepository()should callbuildEnv($repo, forAgent: false)(server-side local access, which the code already supports and uses correctly elsewhere — see theelsebranch a few lines down that setsBORG_BASE_DIR/HOMEforwww-data), orborg initshould operate directly on the local filesystem path (BorgCommandBuilder::getLocalRepoPath(), which the surrounding code already computes for thecreate-repo-dirhelper call a few lines earlier) instead of round-tripping through the repo'sssh://path.Workaround (for anyone hitting this)
SSH_PORTand plain22(e.g. add"22:22"alongside"${SSH_PORT:-2222}:22"indocker-compose.yml), or revertSSH_PORTto 22.borg initstill fails on the identity file, run it manually inside the container aswww-datawithBORG_BASE_DIR/HOMEpointed at a writable cache dir, directly against the local repo path (/var/bbs/home/<agent_id>/<repo_name>) instead of thessh://path.chownthe repo directory (recursively) to the agent's SSH unix user (ssh_unix_usercolumn inagents, e.g.bbs-agent-<n>) rather thanwww-data— otherwise the agent-side backup job fails separately withFailed to create/acquire the lock ... Permission denied, since normal backup/restore traffic connects as that unix user, notwww-data.Steps to reproduce
docker-compose.yml, withSSH_PORTset to anything other than 22 (the compose file's own default is 2222).borg initfailing as above.