|
| 1 | +--- |
| 2 | +title: Connecting to a Client |
| 3 | +--- |
| 4 | + |
| 5 | +The connection is made by PHP, not by your editor. Your editor waits on a port, |
| 6 | +and when a session starts the debugger reaches out to it and opens the connection. |
| 7 | +Nothing listens on the PHP side, so there is no port to expose and nothing to let |
| 8 | +through a firewall on the way in. |
| 9 | + |
| 10 | +So the debugger needs to know which machine and which port to reach. Two settings |
| 11 | +tell it, and on a normal setup both are already right: |
| 12 | + |
| 13 | +| Setting | Default | | |
| 14 | +| --- | --- | --- | |
| 15 | +| `php_debugger.client_host` | `localhost` | Where your editor is | |
| 16 | +| `php_debugger.client_port` | `9003` | The port it listens on | |
| 17 | + |
| 18 | +If your editor and your code run on the same machine, you are done. Change the port |
| 19 | +only if something else already has `9003`, or if you are debugging two projects at |
| 20 | +once and want them apart; whatever you pick has to match what your editor is |
| 21 | +listening on. |
| 22 | + |
| 23 | +Everything below is for the cases where the two are *not* on the same machine. |
| 24 | + |
| 25 | +## When the code runs somewhere else |
| 26 | + |
| 27 | +`localhost` means *this machine*, and inside a container that is the container, not |
| 28 | +you. The fix is to give `client_host` an address that reaches your machine from |
| 29 | +wherever the code runs: |
| 30 | + |
| 31 | +```ini |
| 32 | +php_debugger.client_host=host.docker.internal |
| 33 | +``` |
| 34 | + |
| 35 | +See [Docker](../getting-started/docker.mdx) for the full setup, including the |
| 36 | +`extra_hosts` entry Linux needs to make that name resolve. |
| 37 | + |
| 38 | +### Letting the debugger work the address out |
| 39 | + |
| 40 | +Two special values stand in for an address the debugger finds at runtime. Both are |
| 41 | +**Linux only** — elsewhere they are ignored. |
| 42 | + |
| 43 | +```ini |
| 44 | +php_debugger.client_host=php_debugger://gateway |
| 45 | +``` |
| 46 | + |
| 47 | +`gateway` connects to the gateway of the machine's default route. From inside a |
| 48 | +container that is the host machine, which makes it the native-Linux answer to |
| 49 | +`host.docker.internal` — same result, without the `extra_hosts` entry. |
| 50 | + |
| 51 | +```ini |
| 52 | +php_debugger.client_host=php_debugger://nameserver |
| 53 | +``` |
| 54 | + |
| 55 | +`nameserver` uses the first DNS server the system resolver knows about, and only |
| 56 | +accepts it if it sits in a private range (`10/8`, `172.16/12`, `192.168/16` or |
| 57 | +`127/8`). A public resolver is refused. This one is for setups where your machine |
| 58 | +is also the one answering DNS — some VPN and corporate networks, and VMs pointed at |
| 59 | +the host. |
| 60 | + |
| 61 | +## When the address keeps changing |
| 62 | + |
| 63 | +On a shared or dynamic environment there may be no single address to hard-code. |
| 64 | +`php_debugger.discover_client_host=1` makes the debugger work it out from the |
| 65 | +incoming HTTP request instead, connecting back to whoever made it. |
| 66 | + |
| 67 | +The addresses it looks at, and their order, come from |
| 68 | +`php_debugger.client_discovery_header`, which defaults to: |
| 69 | + |
| 70 | +```ini |
| 71 | +php_debugger.client_discovery_header=HTTP_X_FORWARDED_FOR,REMOTE_ADDR |
| 72 | +``` |
| 73 | + |
| 74 | +The first header present wins, and if it holds a list of addresses the first one is |
| 75 | +used. When no header yields an address — or the address it yields cannot be reached |
| 76 | +— the debugger falls back to `client_host`, so keep that set to something sensible. |
| 77 | + |
| 78 | +:::warning[Only where the request is trustworthy] |
| 79 | + |
| 80 | +`X-Forwarded-For` is a request header, and the request decides its value. On a host |
| 81 | +that is reachable by anyone, that lets a stranger name the address the debugger |
| 82 | +connects to. Use discovery behind a proxy you control, and leave it off otherwise. |
| 83 | + |
| 84 | +::: |
| 85 | + |
| 86 | +Discovery only finds the *host*. The port is always `client_port`. |
| 87 | + |
| 88 | +## How long it waits |
| 89 | + |
| 90 | +`php_debugger.connect_timeout_ms` caps each connection attempt, and defaults to |
| 91 | +`200` milliseconds. Every attempt that finds nothing listening costs the request |
| 92 | +that much, which is why the default is small. |
| 93 | + |
| 94 | +Raise it if the connection has to cross a real network and 200 ms is not enough to |
| 95 | +complete a handshake — a few hundred more is usually plenty. |
| 96 | + |
| 97 | +## Connecting through a relay |
| 98 | + |
| 99 | +`php_debugger.cloud_id` is for the case where the debugger cannot reach your |
| 100 | +machine at all — the code runs behind a firewall or a NAT you do not control, and |
| 101 | +no address you set would connect. Instead of dialing your editor, the debugger |
| 102 | +dials a hosted relay, and your editor connects to the same relay from its side. |
| 103 | + |
| 104 | +```ini |
| 105 | +php_debugger.cloud_id=your-id-here |
| 106 | +``` |
| 107 | + |
| 108 | +The ID comes from the relay service, and both ends must use it. Setting it takes |
| 109 | +priority over `client_host` — leave it empty, as it is by default, and connections |
| 110 | +stay direct. Unlike the other settings on this page, it can only be set in |
| 111 | +`php.ini`. |
| 112 | + |
| 113 | +The relay is a third-party, paid service; see |
| 114 | +[its documentation](https://xdebug.org/docs/cloud) for what it costs and how to get |
| 115 | +an ID. |
0 commit comments