Build a Containerized Status Page
Package a personal status page with Docker, NGINX, and Docker Compose.
Introduction
30 Second Summary
A website can work perfectly on one computer and fail as soon as it moves somewhere else. Small differences in the surrounding setup are often enough to break it.
In this project, you will package a personal status page as a reusable Docker image on Windows. You will use Docker Compose to recreate the finished site from a saved definition.
What You'll Build
At http://localhost:8080, you'll see a dashboard reporting Docker Status: Online from NGINX inside a Linux container.
By the end of this project, you'll have:
- A local dashboard that displays Docker Status: Online at http://localhost:8080.
- A reusable Docker image named status-page:1.0 that restores your personalized site every time you replace its container.
- A Docker Compose workflow that recreates the complete site from compose.yaml with one command.
- An optional Secret Mission: Add a read-only bind mount so saved HTML changes appear without rebuilding the image.
Are there any prerequisites?
You need a supported 64-bit Windows computer with hardware virtualization enabled. Your computer also needs at least 8 GB of RAM.
You should already have Visual Studio Code and a browser installed.
Before We Start
Before the hands-on work begins, define what your status page will show and why packaging it as a container matters to you. This goal gives every Docker concept in the project a clear purpose.
Install and Verify Docker Desktop
Your status-page goal now has a clear destination. Before a Linux container can serve that page, Windows needs a running container engine.
Docker Desktop provides that engine through Docker Engine. Its bundled CLI lets PowerShell send commands to the engine.
In this step, get ready to:
- Verify that WSL 2 meets the required version.
- Install Docker Desktop 4.89.0 with the WSL 2 backend.
- Confirm that the Docker CLI can reach the running engine.
Verify WSL 2
Windows Subsystem for Linux 2 gives Docker Desktop the Linux environment it needs to run Linux containers. Docker Desktop requires WSL version 2.1.5 or later for this setup.
- Press the Windows key to open Windows search.
- Type PowerShell into the search field.
- Start PowerShell with administrator privileges.
- Accept the Windows permission request if it appears.
- Check your installed WSL version by running this command:
wsl --version
What does this command check?
This command asks Windows for details about the installed WSL components. The version result determines whether you can continue or need an update.
✔️ I see the required version
Your WSL version is 2.1.5 or later. Your Windows environment is ready for the Docker Desktop backend.
- Continue to the Docker Desktop installation below.
ⓧ I see an older version
An older WSL version can prevent Docker Desktop from starting correctly. Updating WSL brings its Linux kernel components up to the required level.
- Update WSL by running this command:
wsl --update
What does this command do?
This command downloads the available WSL update from Microsoft. Windows applies the newer WSL components for Docker Desktop to use.
- Restart Windows if the update requests it.
- Return to your administrator PowerShell window after the restart.
- Check the updated version by running this command:
wsl --version
What confirms the update?
The new output reports the WSL components currently installed on Windows. A version of 2.1.5 or later meets Docker Desktop's requirement.
You should now see WSL version 2.1.5 or later.
WSL update not completing?
Confirm that PowerShell has administrator privileges. Check that Windows has an active internet connection.
Still stuck? Help me troubleshoot my WSL update.
ⓧ WSL is missing
Windows needs to install WSL before Docker Desktop can use its Linux backend. This is a one-time system setup.
- Install WSL by running this command:
wsl --install
What does this command do?
This command enables the Windows features required by WSL. Windows may request a restart to finish the installation.
- Restart Windows if requested.
- Use Windows search to start PowerShell with administrator privileges after the restart.
- Check the installed version by running this command:
wsl --version
What confirms the installation?
The output lists the WSL components now available on Windows. A WSL version of 2.1.5 or later is ready for Docker Desktop.
You should now see WSL version 2.1.5 or later.
WSL installation not completing?
Confirm that hardware virtualization is enabled on your computer. Check that PowerShell has administrator privileges.
Need a hand? Help me troubleshoot my WSL installation.
That clears the Windows-specific hurdle. WSL can now provide the Linux foundation for your containers.
Install Docker Desktop
Docker Desktop packages the engine with Docker Build and Docker Compose in one Windows application. This keeps the project focused on container concepts instead of manual engine maintenance.
Why Docker Desktop on Windows?
A manual Docker Engine setup inside WSL adds daemon startup and networking work. Docker Desktop manages those Windows integrations while preserving the Linux-container workflow used throughout this project.
- Press the Windows key to open Windows search.
- Type Docker Desktop into the search field.
- Start Docker Desktop if it appears in the results.
- Select the Docker icon in the Windows taskbar if the application opens.
- Select About Docker Desktop to view the installed version.
- Choose the tab that matches what you found.
✔️ Docker Desktop is current
The version shown is 4.89.0. Keep Docker Desktop open for the backend check below.
ⓧ Docker Desktop needs an update
Your installed release is older than 4.89.0. The current installer upgrades the existing application.
- Visit the official Docker Desktop installer page.
- Download Docker Desktop for Windows version 4.89.0.
- Run the downloaded installer.
- Choose the recommended per-user installation.
- Keep Use WSL 2 instead of Hyper-V selected on the configuration page.
- Complete the installation wizard.
- Restart Windows if requested.
ⓧ Docker Desktop is not installed
Docker Desktop needs to be installed before PowerShell can control containers. The per-user mode is the recommended installation path for this project.
- Visit the official Docker Desktop installer page.
- Download Docker Desktop for Windows version 4.89.0.
- Run the downloaded installer.
- Choose the recommended per-user installation.
- Keep Use WSL 2 instead of Hyper-V selected on the configuration page.
- Complete the installation wizard.
- Restart Windows if requested.
The subscription agreement can make this setup feel like a billing decision. Docker Desktop is free for personal use and education.
- Press the Windows key to open Windows search.
- Type Docker Desktop into the search field.
- Select Docker Desktop from the results.
- Accept the Docker Subscription Service Agreement for this personal-learning project.
- Open Settings from the Docker Desktop Dashboard.
- Select the General tab.
- Select Use the WSL 2 based engine if the setting is visible.
- Select Apply if you changed the setting.
Docker Desktop enables the WSL 2 engine by default on supported systems. The setting may be hidden when WSL 2 is the only available backend.
Docker Desktop not starting?
Confirm that Windows was restarted after the WSL setup. Check that Docker Desktop finished installing under your Windows user account.
Still blocked? Help me troubleshoot Docker Desktop startup.
Verify the client and engine
The Docker CLI uses a client-server model. The CLI is the client in PowerShell while Docker Engine is the server that runs containers.
- Press the Windows key to open Windows search.
- Type Visual Studio Code into the search field.
- Press Enter to start Visual Studio Code.
- Select File from the top menu.
- Select Open Folder....
- Select New Folder.
- Name the new folder docker-status-page.
- Confirm the folder choice to open it as your workspace.
Visual Studio Code may ask whether you trust the new folder. This empty folder belongs to you, so it is safe to trust.
- Trust the docker-status-page folder if prompted.
- Select View from the top menu.
- Select Terminal.
- Confirm that the terminal shell is PowerShell.
- Confirm that the terminal path ends in docker-status-page.
Before you run the first check, do you think the CLI can reach the engine now?
- Test the Docker client-server connection by running this command:
docker version
What does this command prove?
The Client section describes the Docker CLI available to PowerShell. The Server section appears when that CLI reaches Docker Engine.
You should see separate Client and Server sections. This confirms that Docker Desktop is running and the CLI is connected.
Missing the Server section?
Return to Docker Desktop and wait for the application to finish starting. Confirm that the WSL 2 engine setting is enabled.
Need help with the connection? Help me connect the Docker CLI to Docker Engine.
The final check runs a small public Docker image. Its container prints a confirmation message before the --rm option removes it automatically.
Before you run it, do you expect Docker to complete the full image-to-container workflow?
- Run Docker's official verification image with this command:
docker run --rm hello-world
What happens during this test?
Docker downloads the public test image when it is not already available locally. Docker Engine starts a container from that image.
The container prints its message before stopping. The --rm option removes the stopped container automatically.
You should see Hello from Docker! in the terminal. That confirms the CLI and engine completed a container run successfully.
Hello World test not completing?
Confirm that Docker Desktop is still running. Check your internet connection because the first run downloads the public test image.
Still seeing a failure? Help me troubleshoot the Docker Hello World test.
Your Docker setup is ready. Next, you will turn that working engine into a website you can open at localhost.
Launch Your First Web Container
Your Docker setup passed its first engine check in PowerShell. Now you can use that engine to serve a real website from a Linux container.
Containers start isolated from your Windows browser. Port publishing creates a path from localhost port 8080 to NGINX on port 80 inside the container.
In this step, get ready to:
- Run NGINX as a detached container.
- Publish the web server to localhost on port 8080.
- Confirm the default NGINX page in your browser.
Launch the NGINX container
A Docker image is a reusable package containing everything needed to start a container. The pinned NGINX image already contains a working web server.
Why NGINX for this page?
NGINX can serve a static page directly. That keeps this project focused on Docker without adding a framework or package manager.
The first launch may pause while Docker downloads the image. That extra wait is expected on the first run.
- Start the status-page container in detached mode by running this command:
docker run --name status-page -d -p 127.0.0.1:8080:80 nginx:1.30.4-alpine3.24
What does this command do?
- The --name status-page option gives the container a stable name for later commands.
- The -d option keeps the web server running in the background.
- The -p 127.0.0.1:8080:80 option sends traffic from Windows port 8080 to container port 80.
- The nginx:1.30.4-alpine3.24 value selects the pinned NGINX image.
- Confirm PowerShell returns to a prompt after printing the new container identifier.
The web server keeps running in the background because the container started in detached mode.
Container did not start?
- Switch back to Docker Desktop from earlier if PowerShell cannot reach the engine.
- Wait for Docker Desktop to finish starting before trying the command again.
- Stop the conflicting local process if PowerShell reports that port 8080 is already occupied.
Still blocked? Help me diagnose why the status-page container did not start.
Open the published web page
The mapping binds the website to 127.0.0.1. This keeps the learning service accessible only from your computer.
Before you visit the address, predict whether a fresh NGINX image serves a page immediately.
- Press the Windows key to open Windows search.
- Type the name of your installed web browser into the search box.
- Press Enter to open the selected browser.
- Enter http://localhost:8080 in the browser address bar.
- Press Enter to load the published website.
You'll see the default NGINX landing page. That page proves Windows port 8080 reaches NGINX on container port 80.
That is your first web container working end to end.
Default page not loading?
- Check that the browser address is exactly http://localhost:8080.
- Return to the PowerShell terminal from earlier to confirm the launch command did not report an error.
Need another pair of eyes? Help me troubleshoot why the NGINX page is not loading.
Your first container is now serving a website through localhost. Next, you'll replace the default page with your own dashboard. Then you'll test what survives when the container is replaced.
Watch a Container Forget Your Changes
Your NGINX container is already serving its default page at http://localhost:8080. You now have a live place to test your own status page.
A running container can accept file changes. This step tests whether that edit belongs to the container's writable layer or the image behind it.
In this step, get ready to:
- Create the custom Docker status page in index.html.
- Copy the page into the running container to display your customization.
- Replace the container to discover which version of the page returns.
Create the custom status page
The custom page gives you an obvious visual marker for the experiment. Its dark dashboard looks completely different from the default NGINX landing page.
- In the Visual Studio Code Explorer, click New File....
- Type index.html as the file name.
- Press Enter.
- Select the full-code tab below.
- Copy the complete page from the full-code tab.
- Paste the copied page into index.html.
✔️ Awesome, I've got everything!
Your index.html file contains the complete status-page markup shown in the other tab.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docker Status Page</title>
<style>
:root {
color-scheme: dark;
font-family: Inter, system-ui, sans-serif;
background: #0f172a;
color: #e2e8f0;
}
body {
min-height: 100vh;
margin: 0;
display: grid;
place-items: center;
background: radial-gradient(circle at top, #1e3a8a, #0f172a 55%);
}
main {
width: min(680px, calc(100% - 48px));
padding: 40px;
border: 1px solid #334155;
border-radius: 24px;
background: rgba(15, 23, 42, 0.9);
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.35);
}
.status {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 8px 14px;
border-radius: 999px;
background: #052e16;
color: #86efac;
font-weight: 700;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #22c55e;
box-shadow: 0 0 16px #22c55e;
}
h1 {
margin: 24px 0 8px;
font-size: clamp(2rem, 7vw, 4rem);
}
.subtitle {
margin: 0 0 28px;
color: #94a3b8;
font-size: 1.1rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
gap: 14px;
}
.card {
padding: 18px;
border-radius: 16px;
background: #1e293b;
}
.label {
margin: 0 0 8px;
color: #94a3b8;
font-size: 0.8rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.value {
margin: 0;
color: #f8fafc;
font-family: Consolas, monospace;
}
</style>
</head>
<body>
<main>
<div class="status"><span class="dot"></span>Docker Status: Online</div>
<h1>Containerized and running</h1>
<p class="subtitle">This page is packaged inside a reusable Docker image.</p>
<section class="grid" aria-label="Container details">
<article class="card">
<p class="label">Image</p>
<p class="value">status-page:1.0</p>
</article>
<article class="card">
<p class="label">Service</p>
<p class="value">web</p>
</article>
<article class="card">
<p class="label">Port</p>
<p class="value">8080 to 80</p>
</article>
</section>
</main>
</body>
</html>
What does this page contain?
The HTML supplies the status banner plus three cards for the image, service, and port.
The CSS turns that structure into a centered dark dashboard.
The Docker Status: Online banner gives you a clear signal when the custom file is being served.
- Save index.html.
- Confirm index.html appears in the Explorer.
Can't find index.html?
Check that the file sits directly inside the docker-status-page workspace shown in the Explorer.
Check that the file name ends with .html.
Still stuck? Help me check whether index.html is saved in the correct Visual Studio Code workspace.
Copy the page into the running container
The running container has a writable layer for changes made after it starts. Copying your file into that layer changes the page served by this specific container.
- Copy index.html into the running container from the PowerShell terminal by running this command:
docker cp ./index.html status-page:/usr/share/nginx/html/index.html
What does this command do?
- The source path points to index.html in your current workspace.
- The container name targets status-page.
- The destination path overwrites the file served by NGINX at /usr/share/nginx/html/index.html.
- Switch back to the browser displaying http://localhost:8080.
- Refresh the page.
You should see a dark dashboard with Docker Status: Online near the top.
You have your first visible container customization. The running NGINX service is now serving your own page.
Still seeing the default page?
Press Ctrl+F5 to bypass the browser's cached copy.
Confirm the PowerShell terminal is still inside the docker-status-page workspace.
Need help? Help me troubleshoot why NGINX still shows its default page after I copied index.html into the container.
Replace the container and test the change
A container and its source image are separate artifacts. Recreating status-page from the original image tests where your copied file actually lived.
- Remove the running container by running this command:
docker rm --force status-page
What does this command do?
- The forced removal stops the running container.
- The removal releases the status-page name.
- The removal also frees host port 8080 for the replacement container.
Before you recreate it, pause and consider which page you expect the fresh container to serve.
- Recreate status-page from the original NGINX image by running this command:
docker run --name status-page -d -p 127.0.0.1:8080:80 nginx:1.30.4-alpine3.24
What does this command do?
- The command creates a new container named status-page from nginx:1.30.4-alpine3.24.
- Detached mode keeps the container running in the background.
- Port publishing reconnects 127.0.0.1:8080 to port 80 inside the new container.
- Return to the browser displaying http://localhost:8080.
- Press Ctrl+F5 to perform a hard refresh.
You should see the default NGINX landing page again.
That result is intentional. The copied file lived only in the earlier container's writable layer.
You have now proved the image-versus-container distinction. The replacement container started from the unchanged NGINX image.
Still seeing the custom dashboard?
Press Ctrl+F5 again to clear the cached page.
Confirm the replacement container was created from nginx:1.30.4-alpine3.24.
Need help? Help me troubleshoot why the custom page remains after I replaced the container.
Your custom file is still safe in index.html. Next, you'll package that file into a reusable image so every replacement container serves your dashboard.
Build a Reusable Image
Your custom page worked inside one container. Replacing that container restored the default NGINX page because the copied file lived only in its writable layer.
A Docker image provides a reusable source for every new container. In this step, you will define that image with a Dockerfile.
In this step, get ready to:
- Remove the default NGINX container before building its replacement.
- Package your custom status page as status-page:1.0.
- Recreate the container twice to prove the custom page survives replacement.
Package the page with a Dockerfile
The current container still comes from the unchanged NGINX image. Removing it frees its name before you create a replacement from your own image.
- Remove the running default-page container by running this command:
docker rm --force status-page
What does this command do?
The --force option stops the running container before removing it. The local NGINX image remains available as the foundation for your custom image.
PowerShell prints status-page when the named container has been removed.
- Select New File... in the Visual Studio Code Explorer.
- Type Dockerfile in the file name field.
- Press Enter.
- Add the image instructions by pasting this code:
FROM nginx:1.30.4-alpine3.24
COPY index.html /usr/share/nginx/html/index.html
What does this Dockerfile do?
- The FROM instruction chooses nginx:1.30.4-alpine3.24 as the base image.
- The COPY instruction places your local index.html at the static content path served by NGINX.
- Save Dockerfile.
- Confirm the Explorer lists Dockerfile beside index.html.
Dockerfile missing or named incorrectly?
Check that the file is named exactly Dockerfile with no extension. Windows may otherwise save it as a text file.
Make sure Dockerfile appears beside index.html in the docker-status-page workspace.
Still stuck? Help me check my Dockerfile name and location.
✔️ Awesome, I've got everything!
Your saved Dockerfile now packages the existing status page into the NGINX image.
ⓧ I'd like to double check the full code
FROM nginx:1.30.4-alpine3.24
COPY index.html /usr/share/nginx/html/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docker Status Page</title>
<style>
:root {
color-scheme: dark;
font-family: Inter, system-ui, sans-serif;
background: #0f172a;
color: #e2e8f0;
}
body {
min-height: 100vh;
margin: 0;
display: grid;
place-items: center;
background: radial-gradient(circle at top, #1e3a8a, #0f172a 55%);
}
main {
width: min(680px, calc(100% - 48px));
padding: 40px;
border: 1px solid #334155;
border-radius: 24px;
background: rgba(15, 23, 42, 0.9);
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.35);
}
.status {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 8px 14px;
border-radius: 999px;
background: #052e16;
color: #86efac;
font-weight: 700;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #22c55e;
box-shadow: 0 0 16px #22c55e;
}
h1 {
margin: 24px 0 8px;
font-size: clamp(2rem, 7vw, 4rem);
}
.subtitle {
margin: 0 0 28px;
color: #94a3b8;
font-size: 1.1rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
gap: 14px;
}
.card {
padding: 18px;
border-radius: 16px;
background: #1e293b;
}
.label {
margin: 0 0 8px;
color: #94a3b8;
font-size: 0.8rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.value {
margin: 0;
color: #f8fafc;
font-family: Consolas, monospace;
}
</style>
</head>
<body>
<main>
<div class="status"><span class="dot"></span>Docker Status: Online</div>
<h1>Containerized and running</h1>
<p class="subtitle">This page is packaged inside a reusable Docker image.</p>
<section class="grid" aria-label="Container details">
<article class="card">
<p class="label">Image</p>
<p class="value">status-page:1.0</p>
</article>
<article class="card">
<p class="label">Service</p>
<p class="value">web</p>
</article>
<article class="card">
<p class="label">Port</p>
<p class="value">8080 to 80</p>
</article>
</section>
</main>
</body>
</html>
Build the tagged image
The build context supplies the files that Docker can use during a build. The final dot selects your current docker-status-page folder as that context.
An image tag gives the result a stable name. You will use status-page:1.0 whenever you create this version of the site.
- Build the custom image from the saved files by running this command:
docker build -t status-page:1.0 .
What does this build command do?
- The -t option names the result status-page:1.0.
- The final . sends Dockerfile plus index.html from the current folder into the build.
- The build starts from the pinned NGINX image before copying your custom page into the new image.
- Wait for the image build to finish.
- Confirm the final build output shows a completed image tagged as status-page:1.0.
Build unable to find a file?
Confirm the PowerShell terminal is still inside the docker-status-page workspace. The build context must contain both Dockerfile plus index.html.
Check that the COPY line uses the same lowercase spelling as index.html.
Need help? Help me troubleshoot why my Docker image build cannot find its files.
Prove the image survives replacement
Every container created from status-page:1.0 receives the custom HTML stored in that image. Port publishing makes the NGINX server available to your Windows browser.
- Start the first container from your custom image by running this command:
docker run --name status-page -d -p 127.0.0.1:8080:80 status-page:1.0
What does this run command do?
- The command creates a detached container named status-page from your custom image.
- The port mapping sends traffic from localhost port 8080 to the NGINX server on container port 80.
- The 127.0.0.1 address keeps the website available only on your computer.
- Switch back to the browser tab from earlier.
- Press Ctrl+F5 to hard-refresh http://localhost:8080.
You should see the personalized dashboard with Docker Status: Online. The subtitle says that the page is packaged inside a reusable Docker image.
Custom dashboard not loading?
Confirm the build completed before you started the container. A failed build leaves status-page:1.0 unavailable.
Use a hard refresh to clear the browser's cached default NGINX page.
Still seeing the wrong page? Help me trace which image my status-page container is using.
A reusable image should deliver the same page after its container is replaced. This second creation tests whether the customization now belongs to the image.
Before you replace the container, do you expect the custom dashboard to survive this time?
- Replace the running container with another container from the same image by running these commands:
docker rm --force status-page
docker run --name status-page -d -p 127.0.0.1:8080:80 status-page:1.0
What happens during replacement?
- The first command removes the running status-page container.
- The second command creates a new container from status-page:1.0 with the same localhost port mapping.
- Switch back to your browser.
- Press Ctrl+F5 to hard-refresh http://localhost:8080.
You should see Docker Status: Online after the second container creation. That's the proof your personalized page now survives container replacement because it is packaged in status-page:1.0.
Default NGINX page returned?
Check that the second run command ends with status-page:1.0. Using the original NGINX image recreates the default page.
Confirm the saved Dockerfile copied index.html before the image was built.
Need another pair of eyes? Help me find why my recreated container lost the custom page.
Your status page now has a repeatable image behind it. Next, you will record the build plus runtime configuration in Docker Compose.
Run the Project with Docker Compose
Your reusable Docker image now restores the personalized status page every time you replace its container.
The next goal is to make that result repeatable with Docker Compose. Repeated run commands are easy to mistype.
A Compose file records the build context. It also records the image tag plus the port mapping.
In this step, get ready to:
- Free port 8080 for the Compose-managed service.
- Record the web service in compose.yaml.
- Launch the project through Docker Compose.
Define the Compose application
Only one process can use host port 8080 at a time. The standalone status-page container currently owns that port.
- Free port 8080 by running this command:
docker rm --force status-page
What Did This Command Do?
The command force-removes the running status-page container. This releases host port 8080 for Compose.
You should see Docker confirm that status-page was removed. PowerShell then returns to the prompt.
Container Already Missing?
If Docker says the container is missing, the port may already be free. Continue to the Compose definition.
Need help checking the removal? Help me troubleshoot why Docker cannot remove my status-page container.
- Select New File... in the Visual Studio Code Explorer.
- Enter compose.yaml as the filename.
You should see compose.yaml appear beside Dockerfile in the Explorer.
- Define the Compose service by pasting this code into compose.yaml:
services:
web:
build: .
image: status-page:1.0
ports:
- "127.0.0.1:8080:80"
What Does This Configuration Do?
- The services map contains the application components that Compose manages.
- The web service represents your NGINX status page.
- The build: . setting uses the current workspace as the build context.
- The image: status-page:1.0 setting applies the existing local image name plus its tag.
- The quoted port mapping forwards localhost port 8080 to container port 80.
- Save compose.yaml.
- Confirm the Visual Studio Code Explorer lists compose.yaml beside Dockerfile.
Compose File Not Saved?
Check that the filename is exactly compose.yaml. Make sure the file has no extra extension.
If the YAML looks misaligned, preserve the two-space indentation shown above. Help me compare my compose.yaml with the required service definition.
✔️ Awesome, I've got everything!
Your Compose definition is saved. The next check resolves the file before anything starts.
ⓧ I'd like to double check the full code
- Compare your complete compose.yaml with this reference:
services:
web:
build: .
image: status-page:1.0
ports:
- "127.0.0.1:8080:80"
What Should Match?
Your file should contain one web service. Its build context, image tag, plus localhost-only port mapping should match this reference exactly.
Validate the Compose model
Compose resolves your YAML into the application model it plans to use. Validating first catches structural mistakes before a container starts.
Before you run this check, which service details do you expect Compose to resolve?
- Validate the Compose model by running this command:
docker compose config
What Does This Command Check?
The config subcommand parses the Compose file. It then renders the resolved application model.
A successful result proves that Compose understands the service definition. It does not start the service.
- Find web under the resolved services.
- Confirm the build context resolves to the docker-status-page workspace.
- Confirm the image is status-page:1.0.
- Confirm the published host address is 127.0.0.1.
- Confirm host port 8080 maps to container port 80.
The resolved output now describes the same application you previously launched with a longer command. Your runtime settings are stored in a reviewable file.
Compose Validation Failed?
Compare the indentation beneath web with the full-file reference. YAML uses spacing to group each setting.
Check that your terminal is still inside the docker-status-page workspace. Help me fix my Compose validation problem.
Launch the Compose service
The validated model is ready to become a running application. Compose can build the image before starting the service in the background.
Before you launch it, what should Compose create from the resolved model?
- Build the image and start the service by running this command:
docker compose up -d --build
What Does This Command Do?
- The up subcommand creates the Compose-managed service container plus its network.
- The --build option builds the image before the service starts.
- The -d option keeps the service running in the background.
You should see build progress plus startup progress. PowerShell then returns to the prompt while the web service keeps running.
- Return to the browser tab from earlier.
- Refresh the page at http://localhost:8080.
You should see Docker Status: Online above the personalized dashboard. The page should still show status-page:1.0, web, plus 8080 to 80.
Status Page Not Loading?
Check the startup output in PowerShell for a build or port problem. Make sure Docker Desktop is still running.
If another local process owns port 8080, stop that process before repeating the launch command. Help me troubleshoot why my Compose status page is unavailable.
That's your repeatable workflow working. Docker Compose now builds your image from a reviewable file. It also starts the site at the same local address.
Secret mission
Add Live Editing with a Bind Mount
Your reusable image gives you a dependable release artifact, but rebuilding it for every text change slows your feedback loop. Add a read-only bind mount so saved HTML changes appear in the browser without a new image build.
Clean Up Your Resources
Clean Up Your Resources
Everything in this project runs on your Windows computer, so these resources do not create cloud charges. Choose whether to keep the site running, pause its container, or remove the local resources.
Resources you used:
- A Docker Compose web container plus its local network.
- Two local Docker images: status-page:1.0 plus nginx:1.30.4-alpine3.24.
- The docker-status-page project folder containing these three source files: Dockerfile, compose.yaml, index.html.
Keep everything running
No action is needed. This option keeps your live editing workflow ready for more changes.
- Leave the Docker Compose web service running so http://localhost:8080 remains available.
- Keep the docker-status-page folder for future edits.
- Keep Docker Desktop installed for future container projects.
- Keep WSL 2 enabled as the Windows backend.
Pause - I'll come back to this later
Pausing releases the site's active process while preserving its container for later. Your source files plus local images stay available.
- Stop the Compose-managed web service by running this command:
docker compose stop
What Happens When You Pause?
The service stops without removing its container. Its configuration stays ready for a later restart.
- Restart the same service when you return by running this command:
docker compose start
What Happens When You Resume?
The existing container starts again with the same Compose configuration. Your status page returns at http://localhost:8080.
Delete - I don't want to use this again
Removing the local containers plus images looks final because the running site disappears. Your source files remain safe until you delete the project folder in the final action.
- Remove the Compose-managed container and network from the PowerShell terminal from earlier by running this command:
docker compose down
What Does This Remove?
The Compose service container stops and disappears. The local network created for the project is also removed.
- Remove both local images by running these commands:
docker image rm status-page:1.0
docker image rm nginx:1.30.4-alpine3.24
What Happens to the Images?
The first command removes your custom status page image. The second removes the pinned NGINX image from your computer.
- Close the Visual Studio Code window from earlier.
- Use File Explorer to delete the docker-status-page folder from the location where you created it.
You should no longer see the docker-status-page folder in File Explorer. The site at http://localhost:8080 also stops loading.
Nice Work!
Nice Work!
You did it! Your personal status page now runs in a container from a reusable Docker image through Docker Compose.
You've learned how to:
- Set up Docker Desktop with WSL 2. Verify its client and engine from PowerShell. Run the NGINX Docker Official Image as a web container on a localhost-only port.
- Reveal how an edit in a writable container layer disappears after replacement. Build status-page:1.0 from Dockerfile to make the custom dashboard reusable.
- Define a repeatable Docker Compose workflow in compose.yaml. Recreate the status page from a reviewable service definition.
- Secret Mission: Added a read-only bind mount from index.html into the web container. Saved subtitle changes now appear at http://localhost:8080 without rebuilding the image.
Ready to quiz yourself?