Dockerized Web Application

πŸ’€0
Lv 10 XP
← Labs & Projects

Dockerized Web Application

Beginner ⏱ ~2h ⭐ 200 XP DockerDocker ComposeNode.jsNginx

Build a small web app, package it in a Docker image, and run it alongside a reverse proxy with Docker Compose.

What you’ll build

A two-container application: a small Node.js web server, fronted by an Nginx reverse proxy, orchestrated with Docker Compose. By the end you’ll understand images, containers, port mapping, multi-container networking, and the docker compose up workflow that real teams use every day.

πŸ§ͺBuild it step by step
  1. Create the project structure
    mkdir docker-webapp && cd docker-webapp
    mkdir app

    You’ll end up with an app/ folder for the Node server and a couple of config files at the root.

  2. Write a tiny web server

    Create app/server.js:

    const http = require('http');
    const PORT = 3000;
    http
      .createServer((_req, res) => {
        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.end('<h1>Hello from a container! 🐳</h1>');
      })
      .listen(PORT, () => console.log(`Listening on ${PORT}`));

    And app/package.json:

    { "name": "docker-webapp", "version": "1.0.0", "main": "server.js" }
  3. Containerize the app

    Create app/Dockerfile:

    FROM node:20-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm install --omit=dev
    COPY . .
    EXPOSE 3000
    CMD ["node", "server.js"]

    Build and test it on its own first:

    docker build -t webapp ./app
    docker run -p 3000:3000 webapp
    # visit http://localhost:3000, then Ctrl+C
  4. Add an Nginx reverse proxy

    Create nginx.conf at the project root:

    events {}
    http {
      server {
        listen 80;
        location / {
          proxy_pass http://app:3000;
          proxy_set_header Host $host;
        }
      }
    }

    Note http://app:3000 β€” app is the service name Compose will create, and containers reach each other by service name on the shared network.

  5. Orchestrate with Docker Compose

    Create docker-compose.yml at the root:

    services:
      app:
        build: ./app
      proxy:
        image: nginx:alpine
        ports:
          - "8080:80"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf:ro
        depends_on:
          - app

    Bring the whole stack up:

    docker compose up --build

    Open http://localhost:8080. Your request now flows browser β†’ Nginx β†’ Node app, across two containers on a private network Compose created for you.

  6. Operate and tear down
    docker compose ps        # see both services
    docker compose logs -f   # tail combined logs
    docker compose down      # stop and remove everything
πŸ› οΈExtensions to make it yours

Pick one or two to deepen the learning:

  • Add a third service β€” a Redis container β€” and have the Node app increment and display a visit counter.
  • Add a healthcheck to the app service in Compose and watch its status.
  • Use a multi-stage build to shrink the image, and compare sizes with docker images.
  • Push your image to Docker Hub or GitHub Container Registry.

Capture what you tried, what broke, and the commands that fixed it in the project notes below β€” that write-up is where the real learning consolidates.

πŸ“ Project notes & reflections

Auto-saves as you type