fatedier/frp · warning

unknown public key for remoteAddr %q

Error message

unknown public key for remoteAddr %q

What it means

Returned by the SSH gateway's PublicKeyCallback when the connecting client's public key (compared by marshaled key bytes) is not present in the authorized keys map. This is the SSH equivalent of 'permission denied (publickey)': the key file loaded fine, but the presented key was not listed. The remote address is included to help server operators correlate rejections in logs.

Source

Thrown at pkg/ssh/gateway.go:84

		return nil, err
	}
	privateKey, err := ssh.ParsePrivateKey(privateKeyBytes)
	if err != nil {
		return nil, err
	}
	sshConfig.AddHostKey(privateKey)

	sshConfig.NoClientAuth = cfg.AuthorizedKeysFile == ""
	sshConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
		authorizedKeysMap, err := loadAuthorizedKeysFromFile(cfg.AuthorizedKeysFile)
		if err != nil {
			log.Errorf("load authorized keys file error: %v", err)
			return nil, fmt.Errorf("internal error")
		}

		user, ok := authorizedKeysMap[string(key.Marshal())]
		if !ok {
			return nil, fmt.Errorf("unknown public key for remoteAddr %q", conn.RemoteAddr())
		}
		return &ssh.Permissions{
			Extensions: map[string]string{
				"user": user,
			},
		}, nil
	}

	ln, err := net.Listen("tcp", net.JoinHostPort(bindAddr, strconv.Itoa(cfg.BindPort)))
	if err != nil {
		return nil, err
	}
	return &Gateway{
		bindPort:           cfg.BindPort,
		ln:                 ln,
		peerServerListener: peerServerListener,
		sshConfig:          sshConfig,
	}, nil

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Extract the public key of the key you connect with: ssh-keygen -y -f ~/.ssh/yourkey, and append it as a line to the authorized keys file.
  2. Confirm ssh is actually offering that key: connect with `ssh -v` and look at 'Offering public key' lines.
  3. Check the authorized_keys line is well-formed: <type> <base64> [comment], no line wrapping or trailing whitespace.
  4. Remember the map is keyed on key bytes — identical key material in different files still matches; a different comment on the same key also matches.

Example fix

# generate and register a dedicated key
ssh-keygen -t ed25519 -f ~/.ssh/frp_gateway -N ''
ssh-keygen -y -f ~/.ssh/frp_gateway >> /etc/frp/authorized_keys

# connect
ssh -i ~/.ssh/frp_gateway -p <gatewayPort> v0@<frps-host> "tcp 127.0.0.1:22"
Defensive patterns

Strategy: validation

Validate before calling

# client-side preflight: confirm your key is registered before connecting
ssh-keygen -y -f ~/.ssh/frp_gateway | awk '{print $1" "$2}' > /tmp/mypub
sort /tmp/mypub > /tmp/a; sort /etc/frp/authorized_keys | awk '{print $1" "$2}' > /tmp/b
cmp -s /tmp/a /tmp/b && echo registered || echo "key NOT in authorized_keys"

Prevention

When it happens

Trigger: Client runs `ssh -i wrongkey v0@frps-host -p port` where wrongkey's public half is not in AuthorizedKeysFile; or the user regenerated their keypair; or the authorized_keys entry was edited/truncated (key matches by exact marshaled bytes, not by comment or email suffix).

Common situations: Using the default SSH key (~/.ssh/id_ed25519) instead of the key registered with the gateway; authorized_keys entry copied with a broken base64 body or missing key-type prefix; multiple team members sharing one gateway file with stale entries.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/8776215aac04705c. Report an issue: GitHub.