Reaching a private Git server from three machines

zugriff.at · 6 October 2026 · Setup log, with sensitive details removed

This is a record of one working session. It covers how git.zugriff.at is set up, how to reach it, adding a second machine, and an error that came up along the way. Addresses, ports, account names and key fingerprints are replaced with placeholders such as <private-ip>.

The setup

The edge server accepts SSH only over the private network. The firewall blocks it from the internet, and sshd only allows logins from private addresses. The Git account's keys are also tied to the main server's private address. In practice, every Git connection has to come from the main server or pass through it.

Connecting from the main server

This already worked. The SSH config there points the public name at the edge server's private address, uses a dedicated key, and pins the host key:

Host git.zugriff.at
    HostName <edge-private-ip>
    HostKeyAlias <edge-private-ip>
    User <git-user>
    IdentityFile ~/.ssh/git_zugriff_ed25519
    IdentitiesOnly yes
    StrictHostKeyChecking yes

Usage:

ssh <git-user>@git.zugriff.at list            # list repositories
ssh <git-user>@git.zugriff.at create myrepo   # create a bare repository
git clone <git-user>@git.zugriff.at:myrepo.git
git remote add origin <git-user>@git.zugriff.at:myrepo.git

The account's shell is git-shell. You can't log in interactively, and it only accepts list, create and normal Git operations. A test run of list returned three repositories.

Connecting from the laptop

The laptop has no direct route to the edge server. It goes through the main server with ProxyJump, on the main server's SSH port, using a key that the Git account already trusts.

Adding the home server

The home server already reaches the main server through a locked-down jump account. That account can't open a shell. Its key may only forward to one destination, the edge server's SSH port. Because forwarding to that port is already allowed, the jump account's settings didn't need to change. Only the Git account needed a new key.

A different session manages the home server and the jump account. On request, that rule stayed absolute: nothing was changed there from here. The steps below were written up as a handoff for that session to carry out.

  1. Create a dedicated key on the home server, separate from the tunnel key:
    ssh-keygen -t ed25519 -f ~/.ssh/git_zugriff_ed25519 -C "home→git.zugriff.at" -N ""
  2. Add an SSH config entry that jumps through the existing jump-host entry:
    Host git.zugriff.at
        HostName <edge-private-ip>
        HostKeyAlias <edge-private-ip>
        User <git-user>
        IdentityFile ~/.ssh/git_zugriff_ed25519
        IdentitiesOnly yes
        StrictHostKeyChecking yes
        ProxyJump <jump-host-alias>
  3. Pin the edge server's ed25519 host key in known_hosts. Compare the fingerprint over a channel you already trust.
  4. Send the public key back so it can be added to the Git account. It gets the same restrictions as the other keys: restrict, and logins only from the main server's private address.
  5. Test it: ssh <git-user>@git.zugriff.at list.

The home-server session did steps 1–3. It backed up the old SSH config first, and the host key was already pinned with a matching fingerprint. It then sent back the public key.

The jump goes over WireGuard to the main server, but the last hop from the main server to the edge server still comes from the main server's private address. The address restriction on the Git account therefore still matches.

Adding the key on the edge server needed a manual step. Claude Code's auto mode blocked the assistant from reading the Git account's authorized_keys on the production edge server. So instead it handed over a command to run by hand. That command backs up the file, appends the restricted key, and shows the result.

The error: "This account is currently not available"

The first test from the home server printed this message. It comes from nologin. It means something tried to open a login shell for an account that isn't allowed one.

Likely cause: the connection to the jump host asked for a shell instead of only forwarding. That happens if you test with ssh <jump-host-alias> directly, or if the jump entry has RemoteCommand or RequestTTY set. A plain ProxyJump only forwards and never asks for a shell.

The home-server session was asked to check:

ssh -G git.zugriff.at | grep -iE '^(user|hostname|port|proxyjump|proxycommand|identityfile) '
ssh -G <jump-host-alias> | grep -iE '^(user|hostname|port|identityfile|remotecommand|requesttty|proxycommand) '
ssh -v <git-user>@git.zugriff.at list 2>&1 | grep -iE 'proxy|jump|authenticated|offering|channel|not available' | head -40

What a correct setup looks like: the jump entry has no RemoteCommand and no RequestTTY, and it uses the same key the home server already uses for the jump account, with IdentitiesOnly yes. Test with the Git command, not by logging in to the jump host.

Status

Lessons