Getting Your App in the Internet¶
An Introduction to Infrastructure to Host Your App in the Internet
Presented By:
- Frinze Lapuz, Snr. DevEx Software Engineer at Atlassian
What is Developer Experience (DevEx)?
Developer Experience is a particular specialization in the field of SE that focuses on making developers (human or agents) more productive and efficient.
The other way to see it is - DevEx is all about building the system that builds the system (primarily software). That system could include:
- Tools to build the software
- Culture of innovation in the Engineers that build software
- (Or) Harnesses for the agents that build software (or as they call it in today's world - Agentic Software Engineering)
Goal¶
After this workshop, you will be able to:
- Understand what's involved in hosting your app in the internet (from first principles)
Why are we learning from first principles?
First principle allows you to properly understand how each different parts of what we do connect with one another. When you know this first principle, whether you use AWS ECS, Google Cloud Run, Kubernetes, etc. - you'll be able to understand what it does under the hood enough for you to consider how that one particular tech handle the parts that we're doing in this workshop.
Prerequisites¶
- Docker images already published in a public registry (eg. Docker Hub, Github Registry)
- DigitalOcean Account
- Domain name
What do you need to host your app in the internet?¶
- Server (A computer that can run your server-side app such as Django or a "Static File App Server" to serve HTML, CSS, JS)
- Domain Name
- Your app π
sequenceDiagram
Client Browser ->> DNS: my-app.codersforcauses.org
DNS ->> Client Browser: 10.0.0.100
Client Browser ->> Server: GET /
Server ->> Server App: GET /
Server App ->> Server: HTML, CSS, JS file / JSON response
Server ->> Client Browser: HTML, CSS, JS file / JSON response
(Recommended to follow) A Simple Practical Example of a Server: Your Laptop as a Server for your Phone¶
This will not work in more complicated Networking
This is a simple example to help you understand the concept. This will not work for complicated networking such as the one that university has
- Try turning on the hotspot of your phone
- Connect your laptop to the hotspot
- Create a simple html file with the content "Hello, World!" and name it
index.html
1 2 3 4 5 | |
- Using the command below, serve the html file
1 | |
- Confirm that when you go to http://localhost:8000, you see the "Hello, World!" message.
So far in this example - you have the server (your laptop) and the client (your laptop). Your browser requests the html file from the "localhost" address (also known as the "127.0.0.1" address).
Now let's get your phone accessing your laptop's server.
- Run the command below to get your laptop's IP address
1 2 3 | |
Your device can have multiple IP addresses
Your device can have multiple IP addresses. It depends on how many network interfaces your laptop has an how many its connected to.
Eg. if your device supports both WiFi and Ethernet, it will have two IP addresses. One for WiFi and one for Ethernet.
Mac it somewhat looks like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Alternative for Mac
Your current Mac's IP address is viewable in Apple -> About this Mac ->System Report -> Network.
-
On your phone, go to the browser and type in the IP address you got from the previous step
-
You should see the "Hello, World!" message.
Fun fact: Mobile Development
If you're developing on mobile devices, and you want to test it live on your phone connected to your backend, this is somewhat the networking setup you'll need. The phone can talk to your laptop's server via the IP address you got from the previous step.
(Optional If you want to try...) Assigning a "Local Domain Name" to your laptop¶
- On your laptop, create a file called
hostsin the/etc/directory - Add the following line to the file:
1 | |
- Restart the computer
- Now when you go to your laptop and open the browser, you can type in
http://my-app.local:8000to access your app with the local domain name.
Side Story: Malaysia's Interactive Web App for Chinese New Year 2025 in Kuala Lumpur¶
Don't proceed yet until told :)
I got some fun stories for you! so hold on!
Intro
As an engineer working remotely, one of the amazing perks really is to travel and see the world in a daily life!
And of course because of that - back in 2025 I went to Kuala Lumpur it was great!

Exhibition
I went to this mall in the Petronas towers called "Suria KLCC". It looked like this!

One of the things I saw was this interactive web app.
Architecture
If you take a look at the architecture of the system, it will probably just look like this
"Push Architecture"
sequenceDiagram
participant Ipad as Ipad
participant ServerComputer as Server Computer
participant DisplayComputer as Display Computer
Ipad->>ServerComputer: Sent the Details about the Wish `/api/wish`
ServerComputer->>DisplayComputer: (Via Push Notification) Send a request to `/api/display`
DisplayComputer->>DisplayComputer: Change the display to the new wish
"Polling Architecture"
sequenceDiagram
participant Ipad as Ipad
participant ServerComputer as Server Computer
participant DataStore as Data Store
participant DisplayComputer as Display Computer
Ipad->>ServerComputer: Sent the Details about the Wish `/api/wish`
ServerComputer->>DataStore: Store the wish in the data store
loop Polling
DisplayComputer->>ServerComputer: Check if there's a new wish
ServerComputer->>DataStore: Check if there's a new wish
DataStore->>ServerComputer: Wish
ServerComputer->>DisplayComputer: Display the wish
end
Interactive Workshop Time: Taking it now to the cloud!¶
It is highly recommended that you follow along with the workshop
It is highly recommended that you follow along with the workshop. This will help you understand the concepts better because you'll get your hands dirty, see things for yourself!
Congratulations! You have successfully hosted your app already in your local network!
However, there's a couple of things now that you need to consider:
- Your laptop is not always on
- Your laptop is not always connected to the internet with the accessible IP address
- Other devices don't know the "domain name" to get to your laptop.
In this workshop, we'll be focusing on hosting your app in the cloud.
Self-Hosting
If you're interested in what's involved in self-hosting, there's only really a couple of differences.
Firstly, you'll need to set your server up to always have power and always running. The next is, you'll need to configure your server to accessible in the public internet. Your router that you have will have an assigned public IP address. You just need to configure your router to do "port-forwarding" via private IP address to your server.
So imagine a layout a like this: - say your public IP address is 10.0.0.100 - the private IP address of your server is 192.168.1.100 - you need to configure your router to forward requests of port 8000 of 10.0.0.100 to 192.168.1.100
1 2 3 4 5 6 | |
http://10.0.0.100:8000.
For domain name, it will be the same as if you're in the cloud. You just need to configure your DNS to point to your server.
Getting a computer in the cloud¶
For this workshop, we'll be using DigitalOcean as our cloud provider.
You can use other providers such as AWS EC2, GCP Compute Engine, etc.
- Login to DigitalOcean
- Go to Droplet -> Create a new Droplet. Select these options
- Region: Pick a region closest to you (for Perth - it will either be Singapore or Sydney)
- Choose an Image: Go to "Marketplace" and search "Docker" (You'll probably find - "Docker latest on Ubuntu 22.04"). Choose that
- Droplet Type: Just do Basic (but it's up to you)
- CPU Options: Regular (Disk type: SSD).
$6/mo(the lowest possible option) should be enough - Authentication Method: Select SSH Key - then add a new SSH key. Follow the instructions. If this doesn't work, please ask for help.
- Once you've created the Droplet, you'll be able to see the IP address of the Droplet.
-
Connect to the Droplet using the SSH key you added.
1ssh -i ~/.ssh/id_rsa root@<your-droplet-ip-address>If you're using a passphrase, you'll be prompted to enter it.
1Enter passphrase for key '/Users/USER/.ssh/id_rsa':Once you're connected, you can start using the Droplet.
In my case - this is the command i ran
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Why are we choosing from Market place, and not just go to OS?
In this workshop, we are wanting to use "Docker". We'd like it to preferably be preinstalled.
SSH Key Setup
At a basic case you'll do the following
Create a new key pair, if needed Open a terminal and run the following command:
1 | |
You will be prompted to save and name the key.
1 | |
Next you will be asked to create and confirm a passphrase for the key (highly recommended):
1 2 | |
This will generate two files, by default called id_rsa and id_rsa.pub. Next, add this public key.
Add the public key
Copy and paste the contents of the .pub file, typically id_rsa.pub, into the SSH key content field on the left.
1 | |
For more detailed guidance, see How to Add SSH Keys to Droplets
Okay you now have a computer in the cloud!!! π
Let's try serving just some hello world app!¶
- Run the command below to run something in port 80
1 | |
- Check if it's working using
curl(a command-line tool that sends a request to a server, just like a browser does):
1 | |
You should see the same "Hello World" text response printed directly in your terminal.
- You can also check it from your own laptop's browser. Go to the browser and type in the IP address of the Droplet, followed by
:80(the port number) - for examplehttp://<your-droplet-ip-address>:80. You should see
1 2 3 4 5 6 7 8 9 10 11 | |
Now that's a demonstration of you serving something in the wider internet!
Let's add a Recognizable Domain Name to your app!¶
Where do you buy domain names?
You can buy it in multiple providers. If you want recommendations, Namecheap and Cloudflare are good options.
Cloudflare gives you an extra feature about protected DNS by doing "proxy" mode. This means that the IP address associated with the domain name is the IP address of the Cloudflare server. Only when the request is "allowed" (by your rules), the request is forwarded to your server, so you don't expose the IP address of your server to the wider internet.
Here's how it works:
sequenceDiagram
participant Client as Client Browser
participant DNS as DNS Server
participant CF as Cloudflare Proxy
participant Server as Your Server
Client->>DNS: What's the IP for my-app.codersforcauses.org?
DNS-->>Client: Cloudflare's IP (not your server IP)
Client->>CF: GET my-app.codersforcauses.org (request)
CF->>CF: Check security rules
alt Request Allowed β
CF->>Server: Forward request
Server-->>CF: Response (HTML, JSON, etc)
CF-->>Client: Response
else Request Blocked β
CF-->>Client: 403 Forbidden / Error Response
end
Note over Client,Server: Your actual server IP stays hidden! π
Assuming you now have a domain name (or you're borrowing the codersforcauses.org domain name), you can now configure your DNS to point to your server.
Subdomains
For this workshop, we'll give you access to subdomains of codersforcauses.org. We are able to create as much subdomain for you.
You may want to create a subdomain for your app.
Borrow a CFC Laptop logged in to the Cloudflare DNS management page.
Create an "A" record for your subdomain pointed to your server's IP address.
1 | |
Save the changes.
Now you can access your app at http://my-app.codersforcauses.org.
Let's now focus on serving your backend and frontend!¶
What is Docker?
Docker is a way to package your application and its dependencies, so you can easily just run it. It's essentially a way to make your app "portable".
In the previous example, we just took some app in the internet and served it with just one command.
However, what we're about to do in this next section is going to use that same concept (while a bit more complex) to serve your backend and frontend.
For this workshop, I'm modelling the repository django-nextjs-template.
In this template, we publish two docker images:
- Frontend:
ghcr.io/codersforcauses/django-nextjs-template-prod-client(accessible here) - Backend:
ghcr.io/codersforcauses/django-nextjs-template-prod-server(accessible here)
You will may have figured out that we have a "Production Compose Files". This production compose file is essentially used to model the docker container networking.
Getting the files onto your Droplet¶
Before you can run docker compose, you need the docker-compose.prod.yml file (and the other files it references, like the nginx config) on your Droplet.
The easiest way is to clone the whole repository onto your Droplet via SSH:
1 2 | |
Using your own project instead
If you're deploying your own app instead of the example template, clone your own repository instead. Just make sure it has a docker-compose.prod.yml (or similar) file that references your own published Docker images.
Code of the compose
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
Reverse Proxy and Networking¶
Raw Nginx Configuration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
Visually here's what the networking looks like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
This diagram shows:
- Client Browser makes a request to your domain name (e.g.,
my-app.codersforcauses.org) - VPS/Droplet receives the request on port 80 (HTTP) or 443 (HTTPS)
- NGINX Reverse Proxy inspects the request path and routes it:
/api/*β Backend Container (Django, port 8081)/admin/*β Backend Container (Django, port 8081)/static/*β Static Files served from disk (/opt/static_files/)- Default
/β Frontend Container (Next.js, port 3000)
This setup allows you to serve both frontend and backend from a single domain name and port, with NGINX intelligently routing requests to the appropriate service.
Running your app!¶
Setup your .env.prod file. You can use the .env.prod.example file as a template.
1 | |
Now edit .env.prod and fill in the real values (eg. passwords, secret keys). You can use nano (simpler) or vi/vim (more powerful, usually already installed):
1 | |
New to vi/vim? Here's a quick cheat sheet
vi/vim behaves differently to most text editors - it has separate "modes" for typing vs giving commands. If you accidentally open it and don't know how to get out, here's what you need:
1 | |
- Press
ito enter Insert mode - now you can type/edit like normal - Press
Escto leave Insert mode and go back to Command mode - While in Command mode, type
:wqthenEnterto save and quit - While in Command mode, type
:q!thenEnterto quit without saving (if you messed up)
If you're ever stuck, press Esc first, then try one of the : commands above.
Check your docker-compose.prod.yml file to make sure it points to the correct images reference (this will change depennding on what the repo name you have).
Once everything is ready, run
1 | |
You should now be able to access your app at http://my-app.codersforcauses.org.
(Optional) CD (Continuous Deployment / Continuous Delivery)¶
So far we've setup the infrastructure to host your app. However, when you do software development professionally, you will write code all the time, and also make sure your code gets to production.
The process of automating how your code gets to production is called "Continuous Deployment" (sometimes it's referred to as "Continuous Delivery" in a "Product Engineering" context where each code change is a "deliverable").
Here's the complete pipeline:
sequenceDiagram
participant Dev as Developer
participant GitHub as GitHub
participant Actions as GitHub Actions
participant Registry as GitHub Registry
participant Watchtower as Watchtower
participant Server as Your Server
Dev->>GitHub: Push code & create PR
GitHub->>Actions: Trigger workflow (PR merged)
Actions->>Actions: Build Docker image
Actions->>Registry: Publish image
loop Poll every 30 seconds
Watchtower->>Registry: Check for new images
Registry-->>Watchtower: New version found!
end
Watchtower->>Watchtower: Pull new image
Watchtower->>Server: Start new container (blue-green)
Server-->>Watchtower: New container healthy β
Watchtower->>Server: Stop old container
Server-->>Watchtower: Deployment complete β
In this workshop, we've setup "Watchtower" to automatically update your app when you push to the repository. How it works is essentially, whenever there's a new image pushed to the registry, Watchtower will pull it, start the container with the new image and stop the old one.
Because we know that the images pushed to the registry happens only when code is merged to the main branch, this means that whenever you merge your code to the main branch, your app will automatically be picked up and deployed to your server.
For small projects, watchtower is a great way to automate your deployment. However, for larger projects with more critical serving requirements, you may want to use a more sophisticated CD tool (such as AWS ECS), but also other more sophisticated infrastructure setup such as supporting "Blue/Green" deployment, "Canary" deployment, "A/B" testing, etc.
(if none of these buzzwords make sense, search it. You'll learn a lot! π€).
Alternatives to Watchtower
On top of the commercial ones like AWS ECS, Google Cloud Run, etc. - you can use things like Docker Swarm, Kubernetes... Or if you want simpler, there's MicroK8s, k3s, or if you want even simpler... There's making Github actions SSH into your server and run the commands to deploy your app.
But at the end of the day, these are all tradeoffs you gotta make between a number of factors:
- Complexity of the infrastructure
- Cost
- Scalability
- Reliability
- Maintainability
- Security
- Performance
- Availability
- Disaster Recovery
Sometimes if you want to be practical, choose the simplest one that works. A scalable and reliable app is useless if it doesn't have users π, so until you have proper users and you really need it to scale... Choose the simplest one that works!
You're done!¶
Congratulations! You've now successfully hosted your app in the internet! π
You can now start to build your own app and host it in the internet!
This is only a start! There's a lot more advanced techniques and concepts to learn about. However, this should give you a good foundation to start building your own app and hosting it in the internet! As any providers such as Heroku, AWS Lightsail, AWS ECS, AWS EKS, or even Kubernetes! All the concepts you learned today, thats what powers those tech!
If you have any questions, feel free to ask!