Skip to content

Support connecting to destinations by hostname via the agent #4

Description

@facundofarias

Summary

A server configured to connect through a Network Agent must be given the destination's IP address. An internal hostname does not work, even when the machine running the agent can resolve that name itself.

This is surprising to users, who reasonably expect the agent — which sits inside their network and has access to their internal DNS — to perform the lookup.

Current behaviour

The destination hostname is resolved by DeployHQ before the tunnel connection is opened, and only the resulting IP address is sent to the agent. If the name exists only in the customer's internal DNS, that lookup fails and the deployment reports:

Could not resolve hostname

The agent is never asked to resolve anything. The CREATE_REQUEST payload is "<ip>/<port>" — see internal/protocol and the wire format documented in CLAUDE.md — so there is no field in which a name could be carried.

Separately, the access list is IP/CIDR-only, so a name would be rejected with "Destination address not allowed" even if one were forwarded:

  • Go: internal/acl/accesslist.gonet.ParseIP returns nil for a name, so Allows returns false
  • Ruby (deployhq/deploy-agent): lib/deploy_agent/server_connection.rbIPAddr.new(network).include?(destination), which denies on IPAddr::InvalidAddressError

Workarounds available today

  1. Enter the destination's IP address (supported, and what the docs now recommend).
  2. Publish a public DNS record pointing at the internal IP — e.g. an A record for server.example.com10.0.0.5. The name resolves publicly to the internal address, which is then handed to the agent, and the agent connects normally. The IP still needs to be covered by agent.access.

Proposed change

Let the agent resolve destination hostnames itself, using the DNS of the network it runs in.

  • Protocol — decide how to carry a name in CREATE_REQUEST without breaking wire compatibility with deploy-agent v1.4.1. The payload is already a variable-length string so a name may pass through as-is, but older Ruby agents would then reject it at the ACL check — some form of capability negotiation is likely needed.
  • Server side — skip the lookup and forward the name when the destination is proxied through an agent that advertises support. Tracked separately (internal).
  • Agent ACL — name-aware matching. Preferred approach: resolve the name locally and match the resolved IP against the existing IP/CIDR rules. This keeps the access list authoritative and IP-based, so a hostname cannot be used to widen what the agent is permitted to reach.
  • Ruby deploy-agent — decide whether to backport or gate the feature on the Go agent only.
  • Docs — see below.

Docs

The support article on Network Agents previously listed hostnames as valid agent.access entries and used server.local as an example. That has never worked — non-IP entries are silently skipped — and is likely what set the expectation here. Docs are being corrected separately to state that entries must be IPs or CIDR ranges, and to explain that the destination must be given as an IP address.

This repository's README.md was already correct ("Allowed destination IPs/CIDRs").

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions