So I finally sat down and got hands-on with Docker — and not just the hello world
kind of hands-on. I mean building, customizing, pushing, and deploying an Apache web server inside a Docker container, running it on EC2, and even setting up a custom Docker network to simulate more complex environments.
It started off simple. Then got frustrating. Then got cool. Then very frustrating. Then… actually awesome.
If you’re ready to go from “I think I understand Docker…” to “I just built a full web server from scratch using Docker”, then this one’s for you.
Let’s dive in.
🐳 What Is Docker and Why Does It Matter?
Docker is a tool that allows developers to package applications and all their dependencies into lightweight, portable containers.
Why should you care? Because:
- It works everywhere (local, staging, prod).
- You avoid the classic “works on my machine” headache.
- You can version, share, deploy, and replicate environments in seconds.
- It’s the industry standard for modern DevOps and cloud-native apps.
Whether you're developing microservices, testing distributed systems, or just trying to keep your local machine clean, Docker is the go-to tool.
🧰 Prerequisites + What You'll Learn
✅ Prerequisites:
- Basic Linux CLI experience
- EC2 instance running Amazon Linux 2
- Docker installed (we’ll cover that too)
- Public-facing IP and security group rules set
💡 What You'll Learn:
- How to install and use Docker on EC2
- How to create and run a containerized Apache web server
- How to commit + push your image to Docker Hub
- How to create and attach Docker networks
- How to troubleshoot common Docker issues
🔧 Foundational: Docker + Apache on EC2
First, we get Docker installed and running on our EC2 instance.
# 1. Update the package index
sudo yum update -y
# 2. Install Docker
sudo amazon-linux-extras install docker -y
# 3. Start the Docker service
sudo service docker start
Now let’s launch a base Ubuntu container and install Apache inside it:
# Run a Docker Ubuntu container (detached on port 80)
sudo docker run -dit -p 80:80 --name ubuntu-web ubuntu
# Go into the container
sudo docker exec -it ubuntu-web bash
# Update everything inside the container
apt-get update && apt-get upgrade -y
# Install Apache
apt-get install apache2 -y
# Start Apache
service apache2 start
Now check your EC2 public IP in your browser. If port 80 is open in your EC2 security group, you should see Apache’s default page! 🎉
🚀 Advanced: Commit, Push, and Pull Like a Pro
Let’s save this container as a reusable image, push it to Docker Hub, and redeploy it from scratch.
# Exit the container
exit
# Commit the container as an image
sudo docker commit ubuntu-web vvakim/ubuntu-webserver:v1
Before we push it, make sure Docker Hub is properly connected:
# Log in to Docker
docker login
⚠️ Troubleshooting: I had some wild issues here. Even though I got “Login Succeeded,” I wasn’t actually logged in — no username showed in docker info
. Here's the fix:
# Add your user to the Docker group
sudo usermod -aG docker $USER
newgrp docker
# Confirm login
docker info | grep Username
Now push the image:
docker push vvakim/ubuntu-webserver:v1
Test it by removing the old container and pulling from Docker Hub:
docker stop ubuntu-web && docker rm ubuntu-web
# Run the pulled image
docker run -dit -p 8080:80 --name ubuntu-web-alt vvakim/ubuntu-webserver:v1
# Start Apache inside the container
docker exec -it ubuntu-web-alt bash
apachectl start
Check your EC2 public IP on port 8080. Apache is back up, this time from your own Docker image!
🧠 Complex: Networking & Multi-Container Readiness
Let’s simulate a more real-world use case — multiple containers on a shared Docker network.
# Create a custom Docker network
docker network create custom-net
# Run your container using the new network and a different port
docker run -dit --name ubuntu-web-net --network custom-net -p 8081:80 vvakim/ubuntu-webserver:v1
# Start Apache inside the new container
docker exec -it ubuntu-web-net bash
apachectl start
Now check the EC2 public IP on port 8081. You’ve got a second instance running side-by-side!
You can stop and remove the earlier container on 8080 if you want:
docker stop ubuntu-web-alt
docker rm ubuntu-web-alt
🧱 Roadblocks & Fixes
Let’s be real — it wasn’t smooth sailing the whole time. Here are a few issues I hit:
- Apache “site not reached” error — Apache was installed but not running. Minimal Ubuntu images don’t auto-start services, so I used service apache2 start manually.
- Docker login issues — Even with “Login Succeeded,” I wasn’t really logged in. Fixed it by adding my user to the Docker group and logging in again.
- EC2 security group pain — Had to manually allow inbound TCP on ports 80, 8080, and 8081 for browser access.
- Systemctl not working in container — systemctl isn’t supported in minimal Docker images. Stick to service or apachectl.
🎯 Conclusion
So what did we build?
- An Apache web server inside Docker ✅
- A versioned Docker image pushed to Docker Hub ✅
- Networked containers running simultaneously ✅
This project helped me internalize how containers work, how Docker networks operate, and how real-world services get packaged and deployed. If you’re learning DevOps, Docker isn’t optional — it’s foundational.
📬 Follow My Work
Want more DevOps and cloud projects?
📝 Medium
🐙 GitHub
💻 Dev.to
Drop a follow if you liked this one — more hands-on AWS, Docker, and automation content coming soon. 🛠️💡
Top comments (1)
Also check out the automated version of this project here:
dev.to/vvakim/automating-my-docker...