☁️ Pre-Flight Checklist
This is a connecting flight. Before we taxi down the runway, here’s your flight plan. Keep this handy to navigate your flight path.
Welcome aboard the cloud! ☁️
🌥️ Takeoff
⛅️ Cruising Altitude
- How to Set Up Port Forwarding in UTM (macOS + Linux VM)
- How Port Forwarding Relates to OCI Networking
🌤️ Landing & Taxi
Enjoy your flight! ☁️
So far in our series, we've built a local, production-like Ubuntu VM and bridged it to our Mac with a shared folder. We have a clean environment and a seamless coding workflow. Now, we face the final hurdle: networking.
You've written a web application, and you're running it inside the VM. How do you test its API from your Mac? How do you debug the frontend in your browser? By default, the VM is a black box.
This is where port forwarding comes in. It’s not just a local convenience; it’s a fundamental skill that helps you understand and debug one of the most critical components of OCI: Security Lists and Network Security Groups (NSGs). This guide will show you how to configure port forwarding in UTM to complete your local OCI lab.
Why You Need Port Forwarding
UTM's default Shared Network mode acts like a home router for your VM. It uses Network Address Translation (NAT) to give your VM internet access while hiding it behind a virtual firewall. This is great for isolation, but it means your Mac can't directly see the services (or "ports") that your VM opens.
Port forwarding is like creating a special rule on that virtual router. It tells UTM, "Any traffic that arrives at this specific port on my Mac should be forwarded directly to that specific port inside my VM."
You need it to:
- Access a web server in the VM from your Mac's browser.
- SSH into your VM from your Mac's terminal.
- Connect to a database or API running in the VM.
- Develop with frameworks like React, Flask, or FastAPI inside the VM and view the results on your Mac.
How to Set Up Port Forwarding in UTM (macOS + Linux VM)
In these steps, I’ll show you exactly how to set up port forwarding in UTM, test it with a simple Python web server, and troubleshoot common issues.
Step 1: Configure Port Forwarding in UTM
Make sure the VM is powered off before making network changes. Port forwarding changes can’t be made while the VM is running.
Step 2: Open UTM and Select Your VM
- Launch UTM.
- In the main UTM window, select your Ubuntu VM from the list on the left.
- Right-click and select the edit option to open the VM's configuration.
Step 3: Configure the Network
1. In the “Network” tab:
2. Set Network Mode to Emulated VLAN (Shared Network) (sometimes labelled as “NAT”). Once you do that, a Port Forward option will appear below Network
3. Add a Port Forwarding Rule:
Click New and then set:
Field | Example |
---|---|
Protocol | TCP |
Host Address for localhost access) or leave blank for all interfaces. | 127.0.0.1 |
Host Port (Port on your Mac) | 8080 (or any open port) |
Guest Address (IP of the VM) | use 10.0.2.15 or just leave blank to auto-select |
Guest Port (Port on the VM) | 80 (or your app’s port) |
Example: Forward Mac’s localhost:8080
→ VM’s port 80
(where a web server will run).
Use the top labels at the top (i.e., Protocol, Guest Address, Guest Port) to guide you for your entries.
Then save
Step 4: Run a Web Server Inside the VM
Boot into your Linux VM and run:
Install Python (if needed):
sudo apt update
sudo apt install python3 -y
Start a test HTTP server:
sudo python3 -m http.server 80
Note: Port 80 requires sudo. You can also use python3 -m http.server 8080 and adjust the port forwarding accordingly.
Step 5: Test from macOS
From your Mac Terminal, run:
curl http://localhost:8080
You should see an HTML directory listing from the VM — success! Your Mac connected to the VM’s internal web server via localhost:8080
, routed through UTM’s NAT — exactly as intended.
If you curl http://localhost:8080
from your Mac without starting the test server, you get curl: (56) Recv failure: Connection reset by peer
.
Why You’re Seeing a Directory Listing
That’s the default behaviour of:
python3 -m http.server 80
It serves the current directory’s contents over HTTP. Since you’re likely in /
(the root directory) and there are no files there (or permissions restrict listing), the <ul>
is empty.
Troubleshooting Summary
Problem | Fix |
---|---|
curl: (7) Failed to connect | Ensure the VM server is running and port forwarding is saved |
PermissionError: [Errno 13] | Use sudo for ports below 1024 |
Nothing shows in the browser. | Try forwarding to guest port 8080 instead of 80 |
Bonus: Forward Other Services
Service | Guest Port | Host Port | Notes |
---|---|---|---|
SSH | 22 | 2222 | ssh user@localhost -p 2222 |
Flask app | 5000 | 5000 | Run with host='0.0.0.0' |
JupyterLab | 8888 | 8888 | Run with Jupyter Lab --ip=0.0.0.0. |
FastAPI | 8000 | 8000 | Run with uvicorn app:app --host 0.0.0.0 --port 8000 |
React (Vite) | 5173 | 5173 | Run with npm run dev or vite --host (or set "host": true in config) |
React (CRA) | 3000 | 3000 | npm start — override with .env: HOST=0.0.0.0 if needed |
With port forwarding configured, your VM is no longer an isolated box. It's a fully integrated, powerful, and safe extension of your local development environment.
How Port Forwarding Relates to OCI Networking
In OCI, nothing is accessible to the outside world unless you explicitly open a port in a Security List or NSG. Getting a "connection timed out" error because a firewall rule is missing is one of the most common issues developers face.
Port forwarding in UTM is the local equivalent of an OCI ingress rule.
The Problem: Your service is running, but you can't connect.
The OCI Solution: You add an ingress rule to your VCN's Security List for the destination port (e.g.,
allow TCP traffic on port 443 from source 0.0.0.0/0
).The Local VM Solution: You add a port forwarding rule in UTM (e.g., forward host port 8443 to guest port 443).
By practising this locally, you build the muscle memory for cloud networking. You learn to think about which ports your application needs and how to expose them, dramatically speeding up your debugging process when you deploy to a real OCI environment. It turns an abstract networking rule into a tangible, hands-on concept.
Conclusion
With port forwarding configured, your local lab is complete. You have successfully built an isolated, production-mirroring environment that you can code in and network with, all from the comfort of your Mac.
This three-part journey of setting up the VM, creating a shared folder, and configuring port forwarding was about more than just tools. It was about adopting the workflow of a professional cloud engineer. The initial effort to build this environment pays for itself tenfold in saved time, fewer errors in production, and a deeper understanding of how cloud infrastructure truly works. You've eliminated "it works on my machine" from your vocabulary for good.
Cover Photo by BoliviaInteligente on Unsplash
Top comments (0)