Getting Your App in the Internet¶
An Introduction to Infrastructure to Host Your App in the Internet
Presented By:
- Frinze Lapuz, Developer Experience Software Engineer at Atlassian
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 π
I need a mermaid diagram that shows this
1. Client Browser talks to DNS to get IP address for domain name my-app.codersforcauses.org
2. Client Browser contacts the "Computer/Server"
3. Server talks to the Server App (Django or NGINX) to serve the html file, json response
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
(Optional 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) 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.
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 | |
- Go to the browser and type in the IP address of the Droplet. 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 a "CNAME" 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.
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.
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!