Back to Tutorials

Run Your First Docker Container

Learn how to run Nginx, Python, and Node.js containers from scratch using Zenithal.

Prerequisites

  • Docker is installed and running (green status indicator in Zenithal sidebar)
  • The image you want to use is available on Docker Hub or a connected registry

Scenario 1: Nginx Serving a Custom HTML Page

  1. Click Containers in the sidebar
  2. Click the + button (top-right) to open the Run Container sheet
  3. In the Image field, enter: nginx:alpine
  4. Set Container Name to: my-nginx
  5. Expand the Ports section and add a mapping:
    • Host Port: 8080
    • Container Port: 80
    • Protocol: tcp
  6. Expand the Volumes section and add a bind mount:
    • Host Path: click the folder icon and select a local folder (e.g., ~/Projects/my-site)
    • Container Path: /usr/share/nginx/html
    • Read Only: toggle ON (recommended for serving static files)
  7. Click Run

Example File

Create ~/Projects/my-site/index.html before running the container:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello from Zenithal</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: #fff;
        }
        .container {
            text-align: center;
            padding: 2rem;
        }
        h1 { font-size: 3rem; margin-bottom: 0.5rem; }
        p { font-size: 1.2rem; opacity: 0.9; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Hello from Zenithal</h1>
        <p>Served by Nginx inside a Docker container</p>
    </div>
</body>
</html>

Scenario 2: Python HTTP Server

  1. Open the Run Container sheet (Containers → +)
  2. Image: python:3.12-slim
  3. Container Name: my-python
  4. Command: python3 /app/serve.py
  5. Ports: 8000 → 8000 (tcp)
  6. Volumes: bind mount ~/Projects/my-python-app /app (read-only OFF)
  7. Click Run

Example File

Create ~/Projects/my-python-app/serve.py:

serve.py
from http.server import HTTPServer, SimpleHTTPRequestHandler
import os

class MyHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        html = """
        <!DOCTYPE html>
        <html>
        <head><title>Python Server</title></head>
        <body style="font-family: sans-serif; text-align: center; padding: 4rem;">
            <h1>Hello from Python!</h1>
            <p>Running inside Docker via Zenithal</p>
            <p>Host: {host}</p>
        </body>
        </html>
        """.format(host=os.environ.get("HOSTNAME", "unknown"))
        self.wfile.write(html.encode())

if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", 8000), MyHandler)
    print("Server running on port 8000")
    server.serve_forever()

Scenario 3: Node.js Express App

  1. Open the Run Container sheet (Containers → +)
  2. Image: node:20-alpine
  3. Container Name: my-node
  4. Command: sh -c "cd /app && npm install && node app.js"
  5. Ports: 3000 → 3000 (tcp)
  6. Environment Variables: NODE_ENV=development
  7. Volumes: bind mount ~/Projects/my-node-app /app
  8. Click Run

Example Files

Create ~/Projects/my-node-app/package.json:

package.json
{
  "name": "my-node-app",
  "version": "1.0.0",
  "main": "app.js",
  "dependencies": {
    "express": "^4.18.2"
  }
}

Create ~/Projects/my-node-app/app.js:

app.js
const express = require('express');
const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
    res.send(`
        <!DOCTYPE html>
        <html>
        <head><title>Node.js App</title></head>
        <body style="font-family: sans-serif; text-align: center; padding: 4rem;">
            <h1>Hello from Node.js!</h1>
            <p>Express ${require('express/package.json').version} running in Docker</p>
            <p>Environment: ${process.env.NODE_ENV}</p>
        </body>
        </html>
    `);
});

app.listen(PORT, '0.0.0.0', () => {
    console.log(`Server running on port ${PORT}`);
});

What You'll See

  • The container appears in the Containers list with a green "Running" badge
  • Clicking the container name opens the Inspect view with Overview, Env, Network, Mounts, and Resources tabs
  • Open http://localhost:8080 (Nginx), http://localhost:8000 (Python), or http://localhost:3000 (Node) in your browser to see the page

Tips

  • The Mount Path Suggestions feature shows common mount points for known images (e.g., /usr/share/nginx/html for nginx)
  • Toggle Read Only on bind mounts when the container only needs to read files — this prevents accidental writes
  • If a host port is already in use, Zenithal shows a port conflict warning — change the host port to resolve it
  • You can set a Restart Policy (e.g., unless-stopped) in the Advanced section so the container auto-restarts after a Docker restart

Related Tutorials