The quickest way to access a Minikube service from outside the cluster is minikube service <name> --url, which prints a reachable URL for any NodePort or LoadBalancer service. For services of type LoadBalancer, run minikube tunnel in a second terminal and the service gets a real external IP. For a one off debug session, kubectl port-forward works with any driver. Reaching the service from another machine on your LAN takes one more step, because Minikube’s network is private to your host by default.
minikube service myapp --url (NodePort), or minikube tunnel plus kubectl get svc (LoadBalancer), or kubectl port-forward svc/myapp 8080:80 (anything). From other devices on the network: bind port forward to 0.0.0.0, or run kubectl port-forward --address 0.0.0.0, or use an SSH tunnel or socat to relay a host port to minikube ip. Open the port in your host firewall.Which method fits depends on the Minikube driver. With the Docker driver on macOS and Windows, the node IP is not routable from the host, so minikube service silently opens a tunnel for you. With VirtualBox, Hyperkit, HyperV or KVM the node has its own VM IP and NodePorts are reachable directly. This article covers each option in order of effort, then the driver differences, then how to expose a service to other machines. If you have not set up a cluster yet, start with how to install Minikube on Ubuntu.
Start with a service to expose
All examples use a tiny web deployment. Create it once so you can test each method.
kubectl create deployment web --image=nginx:alpine --port=80
kubectl expose deployment web --type=NodePort --port=80 --name=web
kubectl get svc webThe output shows something like 80:31234/TCP. The second number is the NodePort, allocated from the 30000 to 32767 range unless you set nodePort yourself in the service spec.
Method 1: minikube service
This is the command Minikube built for exactly this problem. It looks up the service, figures out how to reach it for your driver, and either opens a browser or prints the URL.
minikube service web # opens the default browser
minikube service web --url # prints http://192.168.49.2:31234
minikube service web -n staging --url
minikube service list # every service with a NodePortOn the Docker driver on macOS or Windows, --url prints a 127.0.0.1 address on a random port and keeps running. That process is a tunnel; close the terminal and the URL stops working. On Linux with the Docker driver, and on all VM drivers, the URL uses the node IP and keeps working after the command exits.
curl $(minikube service web --url). Add --format="{{.IP}}:{{.Port}}" to get just the host and port without the scheme.Method 2: NodePort plus minikube ip
If the node IP is routable from your host, you do not need the helper at all. Get the IP and hit the NodePort directly.
minikube ip # 192.168.49.2 (docker) or 192.168.59.100 (virtualbox)
NODEPORT=$(kubectl get svc web -o jsonpath='{.spec.ports[0].nodePort}')
curl http://$(minikube ip):$NODEPORTThis works on Linux with any driver and on macOS or Windows with VM drivers. It does not work on macOS or Windows with the Docker driver, because the Minikube container lives inside a Linux VM whose bridge network your host cannot see. For the reasons behind each address, read how to get a Minikube IP address.
To pin a specific port, add it to the service spec:
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080Method 3: LoadBalancer with minikube tunnel
Production manifests usually declare type: LoadBalancer. On a cloud provider that provisions a real load balancer; on Minikube the service sits at EXTERNAL-IP <pending> forever unless you run the tunnel.
kubectl expose deployment web --type=LoadBalancer --port=80 --name=web-lb
# in a second terminal, leave it running
sudo minikube tunnel
# back in the first terminal
kubectl get svc web-lb
# EXTERNAL-IP is now populated, for example 10.96.12.34 or 127.0.0.1
curl http://$(kubectl get svc web-lb -o jsonpath='{.status.loadBalancer.ingress[0].ip}')The tunnel creates a network route on the host to the cluster’s service CIDR and needs administrator rights, which is why it prompts for sudo. It also binds ports 80 and 443 on the host when a LoadBalancer service uses them, so anything else on those ports must be stopped first. The official reference is the Minikube handbook page on accessing apps, which is worth keeping open because it documents the driver quirks in detail.
Method 4: kubectl port-forward
Port forwarding bypasses the service network entirely by proxying through the API server, so it works with any driver, any service type, and even ClusterIP services that were never meant to be exposed.
kubectl port-forward svc/web 8080:80
# now http://localhost:8080 reaches the service
kubectl port-forward deployment/web 8080:80 # forward to a pod behind a deployment
kubectl port-forward --address 0.0.0.0 svc/web 8080:80 # listen on all host interfacesThe --address 0.0.0.0 flag is the simplest way to make a Minikube service reachable from a phone or another laptop on the same Wi-Fi. It is also slower than a NodePort and drops long connections occasionally, so treat it as a debugging tool rather than a demo server.
Method 5: Ingress addon
When you have several services, the ingress addon gives you host based routing on ports 80 and 443 through a single entry point.
minikube addons enable ingress
kubectl get pods -n ingress-nginx # wait for the controller to be Running
cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
rules:
- host: web.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
EOF
echo "$(minikube ip) web.local" | sudo tee -a /etc/hosts
curl http://web.localOn macOS and Windows with the Docker driver, the ingress controller is not reachable at minikube ip. Run minikube tunnel and map web.local to 127.0.0.1 instead. Once ingress is in place, tools like Helm charts that ship ingress templates work without modification; see how to install Helm in Minikube.
Driver differences at a glance
| Driver and host OS | NodePort at minikube ip | minikube service –url | LoadBalancer | Reachable from LAN |
|---|---|---|---|---|
| Docker on Linux | Yes | Node IP, persistent | minikube tunnel | Needs relay or port forward |
| Docker on macOS or Windows | No | 127.0.0.1 tunnel, must stay running | minikube tunnel (127.0.0.1) | Needs relay or port forward |
| VirtualBox (any OS) | Yes, host only network | Node IP, persistent | minikube tunnel | Needs relay, or bridged adapter |
| Hyperkit or QEMU on macOS | Yes | Node IP, persistent | minikube tunnel | Needs relay |
| KVM2 on Linux | Yes | Node IP, persistent | minikube tunnel | Needs relay, or libvirt bridge |
The pattern is simple: every driver puts the node on a private network, so “outside the cluster” for your own host is easy and “outside the host” always needs a relay.
Exposing a service to other machines on the LAN
There are three practical relays. Pick the one that matches how long you need it.
Option A: port forward on all interfaces
kubectl port-forward --address 0.0.0.0 svc/web 8080:80
# from another machine
curl http://<your-host-lan-ip>:8080Option B: socat relay to the NodePort
socat is a persistent, low overhead relay that does not depend on kubectl staying connected.
sudo apt install socat # or brew install socat
socat TCP-LISTEN:8080,fork,reuseaddr TCP:$(minikube ip):30080 &Option C: SSH tunnel from the remote machine
If the Minikube host runs an SSH server, the remote user can pull the port to themselves without touching the host configuration.
# run on the remote machine
ssh -L 8080:192.168.49.2:30080 user@minikube-host
# then browse http://localhost:8080 on the remote machineWhatever relay you choose, the host firewall must allow the listening port. On Ubuntu with ufw: sudo ufw allow 8080/tcp. On Fedora or RHEL: sudo firewall-cmd --add-port=8080/tcp. On Windows, add an inbound rule in Windows Defender Firewall with Advanced Security, and on macOS check System Settings > Network > Firewall if it is enabled.
Troubleshooting
minikube service prints a URL but curl times out
On macOS or Windows with Docker, the process that printed the URL must still be running. Also confirm the service has endpoints: kubectl get endpoints web. An empty list means the selector does not match the pod labels, and no amount of networking fixes that.
EXTERNAL-IP stays pending
minikube tunnel is not running, or it is running for a different profile. Check minikube profile list and start the tunnel with -p <profile> if you use more than one cluster. On Linux, run it with sudo so it can add the route.
Connection refused on the NodePort
Either the node IP is not routable (Docker driver on macOS or Windows) or the pod is not listening on the targetPort. Check kubectl logs for the pod and try kubectl port-forward as a control test. If port forward works and NodePort does not, it is a routing problem.
Works on the host, fails from another computer
You are hitting the node IP from the LAN, which never works because the node network is private. Use one of the relays above, then check the host firewall. Test with nc -zv <host-ip> 8080 from the remote machine to separate firewall problems from relay problems.
Service works until a pod restarts
Port forward targets a single pod even when you name a service, so a restarted pod breaks the forward. Re run the command, or use a NodePort or LoadBalancer which go through the service and survive pod churn. Our guide on restarting a pod in Minikube explains why the pod name changes.
Frequently asked questions
What is the difference between minikube service and minikube tunnel?
minikube service targets one NodePort or LoadBalancer service and gives you a URL, opening a temporary tunnel only when the driver needs it. minikube tunnel is cluster wide: it adds a route to the service network so every LoadBalancer service gets an external IP at once, and it keeps running until you stop it.
Can I reach a ClusterIP service from outside?
Not directly, since ClusterIP addresses only exist inside the cluster network. Use kubectl port-forward to proxy to it, change the type to NodePort with kubectl patch, or put an Ingress in front of it. Port forward is the least invasive because it changes nothing in the cluster.
Why does the NodePort range start at 30000?
Kubernetes reserves 30000 to 32767 for NodePorts by default so they never collide with well known ports on the node. You can request a specific port in that range in the service spec. Changing the range itself requires an API server flag and is rarely worth it on Minikube.
Is minikube tunnel safe to leave running?
On a laptop, yes, but it holds a privileged route and may bind ports 80 and 443 on the host. Stop it with Ctrl C so it removes the route. If it is killed without cleanup, run minikube tunnel --cleanup to remove stale routes before starting it again.
How do I expose the Kubernetes dashboard?
Run minikube dashboard --url, which enables the addon and proxies it through the API server, then open the printed address. For LAN access, use kubectl proxy --address 0.0.0.0 --accept-hosts='.*', keeping in mind that this exposes the API without authentication and should only be used on trusted networks.
Wrapping up
For day to day work on your own machine, minikube service --url covers NodePorts and minikube tunnel covers LoadBalancers, with kubectl port-forward as the universal fallback. The driver decides whether the node IP is directly reachable, and the table above tells you which behavior to expect before you waste time on curl.
Reaching the service from other machines is always a relay problem: bind port forward to all interfaces, run socat against the NodePort, or pull the port over SSH, and then open the host firewall. None of these are production patterns, but for demos and shared testing on a LAN they are reliable and take under a minute to set up.
About this article: GeekBlog covers U.S. technology news, AI, phones, smartwatches and gaming. Every story is written and checked under our Editorial Policy. Spotted a mistake or have a story tip? Contact our editors.

