{"course":{"slug":"running-models-yourself","title":"Running Models Yourself","url":"https://addaly.com/learn/running-models-yourself","level":"intermediate","track":"deep"},"lesson":{"slug":"reaching-the-machine-safely","title":"Reaching the machine from somewhere else","url":"https://addaly.com/learn/running-models-yourself/reaching-the-machine-safely","position":57,"of":82,"minutes":9,"answer":"The bind address decides who may connect and reachability decides who can.","keyIdea":"The bind address decides who may connect and reachability decides who can, so keep the server on loopback and carry the connection over SSH or a WireGuard mesh: an unauthenticated inference port is found by scanners within hours, and the abuse that follows is attributable to your machine."},"body":{"format":"markdown","text":"## Two questions people merge into one\n\nWhen a colleague says \"I cannot reach your model\", there are two separate facts in play, and almost every mistake in this area comes from treating them as one.\n\nThe first is the **bind address**: which network interfaces the server is listening on. The second is **reachability**: whether packets from the other machine can arrive at that interface at all. A server bound to `127.0.0.1` will refuse a connection from the next desk even on a perfectly open network. A server bound to `0.0.0.0` behind a strict router will also refuse it. The two failures look identical from the client and have opposite fixes.\n\nCheck the first with one command:\n\n> Figure: Two facts people merge into one complaint. The bind address: who may connect: 127.0.0.1 refuses the next desk as firmly as Brazil; 0.0.0.0 listens on every IPv4 interface; An asterisk in the ss output means IPv6 too; You change it with a flag or an environment variable. Reachability: who actually can: Default-allow IPv6 needs no port forwarding at all; UPnP opens a port without anybody deciding to; Carrier-grade NAT blocks it however you configure; So test from mobile data, not from the next desk. Both failures look identical from the client and have opposite fixes. Scanners sweep the whole address space on the common inference ports within hours, none of these servers ships with authentication, and the abuse that follows is attributable to your machine before it is attributable to anyone else.\n\n```bash\nss -tlnp | grep -E '11434|8000|8080'\n# LISTEN 0 4096 127.0.0.1:11434   -> loopback only\n# LISTEN 0 4096 0.0.0.0:11434     -> every IPv4 interface\n# LISTEN 0 4096 *:11434           -> every interface, IPv4 and IPv6\n```\n\nOn macOS use `lsof -nP -iTCP -sTCP:LISTEN | grep 11434`. Ollama binds to `127.0.0.1:11434` unless you set `OLLAMA_HOST=0.0.0.0`; `llama-server` and vLLM take `--host`. None of them ships with authentication. That is the fact that makes the rest of this lesson necessary.\n\n## What an open inference port actually costs\n\nAn inference server with no authentication on a routable address is a free GPU for anyone who finds it, and finding it is not hard. Internet-wide scanners sweep the whole IPv4 space on common ports in a matter of hours, and there are public search engines whose entire product is the resulting index. Security researchers have repeatedly published counts of thousands of internet-exposed Ollama instances found this way; you do not need to be interesting to be found, only reachable.\n\nWhat happens next is mundane rather than dramatic. Someone pulls your model list, discovers a permissive model, and uses your electricity to generate whatever they want. Some engines' management endpoints let a caller pull new models onto your disk or delete the ones you have. Your logs then contain other people's prompts, and any output produced came from your machine and your IP address. That last point is the one that catches people: the abuse is attributable to you before it is attributable to anyone else.\n\n> The failure mode is not that somebody steals your weights. Everyone can download those. It is that they use your compute and your name.\n\n## \"I never forwarded a port\" is not a defence\n\nTwo mechanisms put machines online without anybody deliberately doing it.\n\n**IPv6.** Many home connections hand every device a globally routable IPv6 address. There is no NAT in front of it. Whether it is reachable depends entirely on the router's firewall, and some pass inbound IPv6 with a default-allow rule. A laptop that has never had a port forwarded can be directly addressable from anywhere. `*:11434` in the `ss` output means you are listening on that address too.\n\n**UPnP.** Some applications ask the router to open a port automatically. The router complies silently. Turning UPnP off in the router settings is a five-minute job worth doing once.\n\nThe inverse also catches people: on a mobile or fibre connection behind carrier-grade NAT you share one public address with hundreds of other subscribers and cannot receive inbound connections at all, no matter what you configure. That is why forwarding rules sometimes appear to do nothing.\n\n## Three ways in, in order of preference\n\n**An SSH tunnel**: free, already installed, per-person by construction:\n\n```bash\nssh -N -L 11434:127.0.0.1:11434 you@workstation\n# now http://127.0.0.1:11434 on the laptop is the workstation's server\n```\n\nThe server stays bound to loopback. Access is exactly the set of people who have an SSH key on that machine, and you revoke it by deleting a line from `authorized_keys`. For one or two people this is the whole answer and needs nothing else.\n\n**A WireGuard mesh**: the right answer for a team or for your own several devices. Plain WireGuard is free and self-hosted; Tailscale puts a usable control plane on top of it with a free personal tier, and Headscale is a free open-source control server if you would rather not depend on a company for key exchange. Each device gets a stable private address, nothing is published to the internet, and a lost laptop is removed centrally. The honest caveat: a managed mesh means a third party coordinates your keys, though it never sees your traffic.\n\n**A reverse proxy on a public hostname**: Caddy or nginx terminating TLS, with authentication in front. Only reach for this when genuine strangers must connect, and never without the gateway from the next lesson. Cloudflare Tunnel achieves the same without an inbound port.\n\n## Verify from the other side\n\nDo not trust the configuration; test it. From a machine that should *not* have access: a phone on mobile data is ideal, because it is outside your LAN and outside your VPN:\n\n```bash\ncurl -m 5 http://your.public.ip:11434/api/tags\n```\n\nA timeout is the correct result. A JSON model list means you are serving the internet. Run the same probe over IPv6 with `curl -6 -m 5 'http://[your:v6:addr]:11434/api/tags'`, because that is the one people forget."},"check":{"question":"Someone checks their router, confirms no port forwarding rules exist, and binds their inference server to 0.0.0.0. Why might it still be reachable from the internet?","options":[{"text":"Home connections often hand each device a globally routable IPv6 address with no NAT, and some routers allow inbound IPv6 by default.","correct":true},{"text":"Binding to 0.0.0.0 only affects IPv4, so the IPv6 listener is a separate service that needs disabling.","correct":false,"tempting":"Mixes up the listener with the path to it; a single process usually listens on both families, and the exposure comes from routing and the firewall, not from a second service."},{"text":"Port forwarding is only required for privileged ports below 1024, and 11434 sits above that range, so a consumer router passes it through to the host automatically.","correct":false,"tempting":"Invents a rule that does not exist; the privileged-port distinction governs which local users may bind a port, not whether a router forwards it."},{"text":"It cannot be reachable, because without a forwarding rule NAT has no destination to send inbound packets to.","correct":false,"tempting":"True for IPv4 alone, which is exactly why this case surprises people: the IPv6 path does not involve NAT at all."}]},"prev":{"slug":"serving-it-to-others","title":"Serving it to other people","url":"https://addaly.com/learn/running-models-yourself/serving-it-to-others"},"next":{"slug":"a-gateway-in-front","title":"A gateway in front: keys, quotas and a bill","url":"https://addaly.com/learn/running-models-yourself/a-gateway-in-front"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Reaching the machine from somewhere else', in Running Models Yourself. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/running-models-yourself/reaching-the-machine-safely (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Reaching the machine from somewhere else","courseTitle":"Running Models Yourself","module":{"index":7,"slug":"serving-it-to-others","title":"Serving it to other people"},"answer":null,"keyIdea":"The bind address decides who may connect and reachability decides who can, so keep the server on loopback and carry the connection over SSH or a WireGuard mesh: an unauthenticated inference port is found by scanners within hours, and the abuse that follows is attributable to your machine.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure","figure":{"left":{"title":"The bind address: who may connect","items":["127.0.0.1 refuses the next desk as firmly as Brazil","0.0.0.0 listens on every IPv4 interface","An asterisk in the ss output means IPv6 too","You change it with a flag or an environment variable"]},"type":"compare","right":{"title":"Reachability: who actually can","items":["Default-allow IPv6 needs no port forwarding at all","UPnP opens a port without anybody deciding to","Carrier-grade NAT blocks it however you configure","So test from mobile data, not from the next desk"]},"title":"Two facts people merge into one complaint","caption":"Both failures look identical from the client and have opposite fixes. Scanners sweep the whole address space on the common inference ports within hours, none of these servers ships with authentication, and the abuse that follows is attributable to your machine before it is attributable to anyone else."},"alt":"Figure: Two facts people merge into one complaint. The bind address: who may connect: 127.0.0.1 refuses the next desk as firmly as Brazil; 0.0.0.0 listens on every IPv4 interface; An asterisk in the ss output means IPv6 too; You change it with a flag or an environment variable. Reachability: who actually can: Default-allow IPv6 needs no port forwarding at all; UPnP opens a port without anybody deciding to; Carrier-grade NAT blocks it however you configure; So test from mobile data, not from the next desk. Both failures look identical from the client and have opposite fixes. Scanners sweep the whole address space on the common inference ports within hours, none of these servers ships with authentication, and the abuse that follows is attributable to your machine before it is attributable to anyone else."}},"blocks":[{"t":"h2","id":"two-questions-people-merge-into-one","runs":[{"text":"Two questions people merge into one"}]},{"t":"p","runs":[{"text":"When a colleague says “I cannot reach your model”, there are two separate facts in play, and almost every mistake in this area comes from treating them as one."}]},{"t":"p","runs":[{"text":"The first is the "},{"text":"bind address","b":true},{"text":": which network interfaces the server is listening on. The second is "},{"text":"reachability","b":true},{"text":": whether packets from the other machine can arrive at that interface at all. A server bound to "},{"text":"127.0.0.1","code":true},{"text":" will refuse a connection from the next desk even on a perfectly open network. A server bound to "},{"text":"0.0.0.0","code":true},{"text":" behind a strict router will also refuse it. The two failures look identical from the client and have opposite fixes."}]},{"t":"p","runs":[{"text":"Check the first with one command:"}]},{"t":"code","lang":"bash","label":"Bash","text":"ss -tlnp | grep -E '11434|8000|8080'\n# LISTEN 0 4096 127.0.0.1:11434   -> loopback only\n# LISTEN 0 4096 0.0.0.0:11434     -> every IPv4 interface\n# LISTEN 0 4096 *:11434           -> every interface, IPv4 and IPv6"},{"t":"p","runs":[{"text":"On macOS use "},{"text":"lsof -nP -iTCP -sTCP:LISTEN | grep 11434","code":true},{"text":". Ollama binds to "},{"text":"127.0.0.1:11434","code":true},{"text":" unless you set "},{"text":"OLLAMA_HOST=0.0.0.0","code":true},{"text":"; "},{"text":"llama-server","code":true},{"text":" and vLLM take "},{"text":"--host","code":true},{"text":". None of them ships with authentication. That is the fact that makes the rest of this lesson necessary."}]},{"t":"h2","id":"what-an-open-inference-port-actually-costs","runs":[{"text":"What an open inference port actually costs"}]},{"t":"p","runs":[{"text":"An inference server with no authentication on a routable address is a free GPU for anyone who finds it, and finding it is not hard. Internet-wide scanners sweep the whole IPv4 space on common ports in a matter of hours, and there are public search engines whose entire product is the resulting index. Security researchers have repeatedly published counts of thousands of internet-exposed Ollama instances found this way; you do not need to be interesting to be found, only reachable."}]},{"t":"p","runs":[{"text":"What happens next is mundane rather than dramatic. Someone pulls your model list, discovers a permissive model, and uses your electricity to generate whatever they want. Some engines’ management endpoints let a caller pull new models onto your disk or delete the ones you have. Your logs then contain other people’s prompts, and any output produced came from your machine and your IP address. That last point is the one that catches people: the abuse is attributable to you before it is attributable to anyone else."}]},{"t":"quote","runs":[{"text":"The failure mode is not that somebody steals your weights. Everyone can download those. It is that they use your compute and your name."}]},{"t":"h2","id":"i-never-forwarded-a-port-is-not-a-defence","runs":[{"text":"“I never forwarded a port” is not a defence"}]},{"t":"p","runs":[{"text":"Two mechanisms put machines online without anybody deliberately doing it."}]},{"t":"p","runs":[{"text":"IPv6.","b":true},{"text":" Many home connections hand every device a globally routable IPv6 address. There is no NAT in front of it. Whether it is reachable depends entirely on the router’s firewall, and some pass inbound IPv6 with a default-allow rule. A laptop that has never had a port forwarded can be directly addressable from anywhere. "},{"text":"*:11434","code":true},{"text":" in the "},{"text":"ss","code":true},{"text":" output means you are listening on that address too."}]},{"t":"p","runs":[{"text":"UPnP.","b":true},{"text":" Some applications ask the router to open a port automatically. The router complies silently. Turning UPnP off in the router settings is a five-minute job worth doing once."}]},{"t":"p","runs":[{"text":"The inverse also catches people: on a mobile or fibre connection behind carrier-grade NAT you share one public address with hundreds of other subscribers and cannot receive inbound connections at all, no matter what you configure. That is why forwarding rules sometimes appear to do nothing."}]},{"t":"h2","id":"three-ways-in-in-order-of-preference","runs":[{"text":"Three ways in, in order of preference"}]},{"t":"p","runs":[{"text":"An SSH tunnel","b":true},{"text":": free, already installed, per-person by construction:"}]},{"t":"code","lang":"bash","label":"Bash","text":"ssh -N -L 11434:127.0.0.1:11434 you@workstation\n# now http://127.0.0.1:11434 on the laptop is the workstation's server"},{"t":"p","runs":[{"text":"The server stays bound to loopback. Access is exactly the set of people who have an SSH key on that machine, and you revoke it by deleting a line from "},{"text":"authorized_keys","code":true},{"text":". For one or two people this is the whole answer and needs nothing else."}]},{"t":"p","runs":[{"text":"A WireGuard mesh","b":true},{"text":": the right answer for a team or for your own several devices. Plain WireGuard is free and self-hosted; Tailscale puts a usable control plane on top of it with a free personal tier, and Headscale is a free open-source control server if you would rather not depend on a company for key exchange. Each device gets a stable private address, nothing is published to the internet, and a lost laptop is removed centrally. The honest caveat: a managed mesh means a third party coordinates your keys, though it never sees your traffic."}]},{"t":"p","runs":[{"text":"A reverse proxy on a public hostname","b":true},{"text":": Caddy or nginx terminating TLS, with authentication in front. Only reach for this when genuine strangers must connect, and never without the gateway from the next lesson. Cloudflare Tunnel achieves the same without an inbound port."}]},{"t":"h2","id":"verify-from-the-other-side","runs":[{"text":"Verify from the other side"}]},{"t":"p","runs":[{"text":"Do not trust the configuration; test it. From a machine that should "},{"text":"not","i":true},{"text":" have access: a phone on mobile data is ideal, because it is outside your LAN and outside your VPN:"}]},{"t":"code","lang":"bash","label":"Bash","text":"curl -m 5 http://your.public.ip:11434/api/tags"},{"t":"p","runs":[{"text":"A timeout is the correct result. A JSON model list means you are serving the internet. Run the same probe over IPv6 with "},{"text":"curl -6 -m 5 'http://[your:v6:addr]:11434/api/tags'","code":true},{"text":", because that is the one people forget."}]}],"check":{"question":[{"text":"Someone checks their router, confirms no port forwarding rules exist, and binds their inference server to 0.0.0.0. Why might it still be reachable from the internet?"}],"options":[{"text":[{"text":"Home connections often hand each device a globally routable IPv6 address with no NAT, and some routers allow inbound IPv6 by default."}],"correct":true,"tempting":null},{"text":[{"text":"Binding to 0.0.0.0 only affects IPv4, so the IPv6 listener is a separate service that needs disabling."}],"correct":false,"tempting":[{"text":"Mixes up the listener with the path to it; a single process usually listens on both families, and the exposure comes from routing and the firewall, not from a second service."}]},{"text":[{"text":"Port forwarding is only required for privileged ports below 1024, and 11434 sits above that range, so a consumer router passes it through to the host automatically."}],"correct":false,"tempting":[{"text":"Invents a rule that does not exist; the privileged-port distinction governs which local users may bind a port, not whether a router forwards it."}]},{"text":[{"text":"It cannot be reachable, because without a forwarding rule NAT has no destination to send inbound packets to."}],"correct":false,"tempting":[{"text":"True for IPv4 alone, which is exactly why this case surprises people: the IPv6 path does not involve NAT at all."}]}],"order":[1,0,2,3],"why":null},"prev":{"slug":"serving-it-to-others","title":"Serving it to other people","minutes":9},"next":{"slug":"a-gateway-in-front","title":"A gateway in front: keys, quotas and a bill","minutes":9}}}