A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

Image
I’m excited to share a set of mobile apps I’ve recently completed and published on both the Google Play Store and the Apple App Store. These apps are designed with a simple goal in mind: to make meaningful, structured content more accessible, whether you’re studying theology or improving your English vocabulary. 📱 Now Available on Both Platforms All apps are live and available for download: Google Play Developer Page: https://play.google.com/store/apps/dev?id=5835943159853189043 Apple App Store Developer Page: https://apps.apple.com/ca/developer/q-z-l-corp/id1888794100 📖 Theology & Confession Study Apps For those interested in Reformed theology and classical Christian teachings, I’ve developed a series of apps that present foundational texts in a clean, focused reading format: The Belgic Confession Canons of Dort Heidelberg Catechism Westminster Shorter Catechism Each app is designed to provide a distraction-free experience, making it easier to read, reflect, and revisit these im...

How to Host a Website on an Oracle Cloud VPS Without a Public IP Using Cloudflare Tunnel

 

How to Host a Website on an Oracle Cloud VPS Without a Public IP Using Cloudflare Tunnel

You don't need a public IP address, an open firewall port, or an SSL certificate installed on your server to host a website.

In this tutorial, I'll show you how to publish a simple Python HTTP server running on an Oracle Cloud Infrastructure (OCI) VPS through Cloudflare Tunnel.

The interesting part is that my OCI VPS has no public IP address, but the website is still accessible from anywhere using HTTPS.

We'll build a simple Hello World page and make it available at:

https://qzlapp.us.ci/blog



1. Architecture

Here is how the connection works:

                  Internet
                     |
                     v
             https://qzlapp.us.ci/blog
                     |
                     v
              Cloudflare Edge
              DNS + HTTPS
                     |
                     v
              Cloudflare Tunnel
                     |
                     v
               OCI VPS
             localhost:8000
                     |
                     v
             Python HTTP Server

Cloudflare Tunnel establishes an outbound connection from the VPS to Cloudflare. External visitors connect to Cloudflare, and Cloudflare forwards their requests through that tunnel.

This means:

  • The VPS does not need a public IP address.

  • No inbound HTTP or HTTPS ports need to be opened on the VPS.

  • Cloudflare handles public HTTPS connections.

  • The Python application can continue using plain HTTP locally.

2. Prerequisites

Before starting, I already have:

  • An Oracle Cloud ARM64 VPS running Oracle Linux 9.

  • 2 OCPUs and 12 GB RAM.

  • No public IP address assigned to the VPS.

  • A Cloudflare account.

  • A domain, qzlapp.us.ci, added to Cloudflare.

  • An active Cloudflare Tunnel connected to the VPS.

I previously registered this free subdomain and configured its nameservers to use Cloudflare.

If you haven't created a tunnel yet, see the Cloudflare Tunnel documentation:

https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/

3. Create a Published Application Route

In the Cloudflare dashboard, open:

Networking → Tunnels → Your Tunnel → Routes

Add a new Published Application route.

For this experiment, use:

SettingValue
Hostnameqzlapp.us.ci
Path^/blog
Service TypeHTTP
Service URLlocalhost:8000

The hostname identifies the public domain, while the path specifies which requests should match this route.

Cloudflare also creates the corresponding DNS record pointing to the tunnel.

No VPS public IP address is required.

4. Create a Python HTTP Server on the VPS

My VPS already has Python 3 installed, so there is no need to install Node.js or any additional web server.

First, create a directory:

mkdir -p ~/hello-blog
cd ~/hello-blog

Create a Python file:

nano hello.py

Add the following code:

from http.server import HTTPServer, BaseHTTPRequestHandler

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path.startswith("/blog"):
            content = b"""
            <html>
                <head>
                    <title>My First Blog</title>
                </head>
                <body>
                    <h1>Hello World!</h1>
                    <p>My first website running on OCI VPS.</p>
                    <p>Exposed through Cloudflare Tunnel.</p>
                </body>
            </html>
            """

            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.send_header("Content-Length", str(len(content)))
            self.end_headers()
            self.wfile.write(content)
        else:
            self.send_error(404, "Not Found")

server = HTTPServer(("127.0.0.1", 8000), Handler)

print("Server running at http://127.0.0.1:8000")
server.serve_forever()

Start the server:

python3 hello.py

The server now listens on:

http://127.0.0.1:8000

Notice that it listens on 127.0.0.1, not 0.0.0.0.

This is intentional. The application only needs to accept connections from the local machine because Cloudflare Tunnel runs on the same VPS.

5. Test the Application Locally

Open another terminal session on the VPS and execute:

curl http://127.0.0.1:8000/blog

You should see the HTML response containing:

<h1>Hello World!</h1>

If this works, the Python application is running correctly.

One important detail: run this command on the VPS itself, not in Oracle Cloud Shell. localhost always refers to the machine where the command is executed.

6. Access the Website Through HTTPS

Now open your browser:

https://qzlapp.us.ci/blog

You should see:

Hello World!

My first website running on OCI VPS.

Exposed through Cloudflare Tunnel.

The request travels through Cloudflare and reaches the Python server on port 8000.

The VPS does not need to install or manage its own public SSL certificate. Cloudflare provides the HTTPS connection at its edge.

7. Where Does the Domain's IP Address Point?

Let's run a simple DNS lookup:

dig qzlapp.us.ci +short

My domain currently resolves to a Cloudflare IP address:

172.67.130.206

This is a Cloudflare-owned IP address, not the public IP address of my OCI VPS.

Cloudflare uses a reverse proxy and Anycast network to handle incoming traffic.

We can also test the HTTPS response:

curl -I https://qzlapp.us.ci/blog

The important distinction is that DNS points visitors to Cloudflare, not directly to the VPS.

My OCI VPS remains behind the outbound tunnel connection.

8. Can One Tunnel Host Multiple Applications?

Yes!

One Cloudflare Tunnel can publish multiple applications using different hostnames and local ports.

For example:

Public URLLocal Service
qzlapp.us.ci/bloglocalhost:8000
api.qzlapp.us.cilocalhost:3000
browser.qzlapp.us.cilocalhost:9222
admin.qzlapp.us.cilocalhost:8080

Each published application route can direct traffic to a different local service.

You don't need to create a separate tunnel for every application.

This makes Cloudflare Tunnel particularly interesting for a small self-hosted server.

Conclusion

I have successfully published a website running on my Oracle Cloud VPS without assigning it a public IP address.

The setup uses:

  • Oracle Cloud Infrastructure for computing.

  • Python for a simple HTTP application.

  • Cloudflare DNS for domain resolution.

  • Cloudflare Tunnel for secure connectivity.

  • Cloudflare Edge for public HTTPS access.

The entire experiment requires very little infrastructure.

It also opens up many possibilities: hosting APIs, dashboards, browser automation services, and other self-hosted applications on the same VPS.

A server without a public IP address can still serve websites to the entire Internet.

That's the interesting thing about Cloudflare Tunnel.


This is a simple proof of concept. For production use, run the application as a managed service, configure appropriate authentication and access controls, and use a production-ready application server.

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular Posts

A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

react-native run-android : do not build/update modified code(App.js)