On-Prem Docker Deployment — Step-by-step

On-Prem Docker Deployment — Step-by-step



Author- Vikramsinh Shinde
date - 2-Dec-2025

Audience:
 Developers / DevOps engineers with basic Linux and Docker knowledge.


Objective:
Deploy a simple web service using Docker and Docker Compose on an on-prem Linux server and document every step used in blog/tutorial. 


Table of Contents

  1. Introduction

  2. Prerequisites

  3. Project structure

  4. Create the custom NGINX Docker image

    • index.html

    • Dockerfile

    • Build & verify

  5. Create docker-compose.yml

    • Explanation of options used

    • Start the stack

  6. Create systemd service to manage docker-compose

    • Why systemd

    • Service file content

    • Enable & start

  7. Configure log rotation for container logs

    • Why

    • Logrotate config

    • Test

  8. Testing the service

    • curl 

    • docker ps and logs

  9. Troubleshooting

    • Common errors & fixes

  10. Lesson Learned 

  11. Conclusion & next steps


1. Introduction

This guide documents an on-prem deployment of a simple NGINX web service using Docker and Docker Compose. It includes file contents, commands to run, systemd integration to manage the Compose stack, log rotation for container logs, and tests.



2. Prerequisites

  • A Linux machine (Ubuntu/Debian/CentOS) with root or sudo access.

  • Docker installed and functional.

  • Docker Compose installed (/usr/bin/docker-compose or Compose v2 plugin).

  • curl for testing.

  • Basic understanding of systemd for service management.

Example working directory used in this guide: /on-prem

3. Project structure

root@on-prem-server:/on-prem# tree
.
├── docker-compose.yml
├── dockerfile
├── html
│   └── index.html
└── logs

Create the folder and move into it:

sudo mkdir -p /on-prem/html /on-prem/logs
cd /on-prem
sudo chown $USER:$USER /on-prem





4. Create the custom NGINX Docker image

html/index.html

Create a simple HTML page that confirms the on-prem deployment:

<!DOCTYPE html>
<html>
<head>
    <title>On-Prem Docker Deployment</title>
</head>
<body>
    <h1>Hello from On-Prem NGINX Docker!</h1>
    <p>Deployed using Docker Compose and managed by systemd.</p>
</body>
</html>

Save it to /on-prem/html/index.html.

Dockerfile

Create a Dockerfile that uses the official NGINX image and copies the custom HTML:

FROM nginx:latest

# Remove default HTML
RUN rm -rf /usr/share/nginx/html/*

# Copy custom content
COPY html/ /usr/share/nginx/html/

# Expose container port
EXPOSE 80

Build & Verify image (optional manual build)

cd /on-prem
sudo docker-compose build
# or
sudo docker build -t on-prem_web .

# Verify
sudo docker images | grep on-prem_web

5. Create docker-compose.yml

Create /on-prem/docker-compose.yml:

version: '3.9'

services:
  web:
    build: .
    container_name: onprem-nginx
    ports:
      - "8080:80"
    restart: always
    volumes:
      - ./logs:/var/log/nginx

Notes:

  • restart: always ensures the container restarts after host reboots.

  • ./logs is bind-mounted so logs are available on the host and manageable by logrotate.

Start the stack:

cd /on-prem
sudo docker-compose up -d
sudo docker ps

6. Create systemd service to manage docker-compose

Why systemd?

Using systemd allows the Compose stack to be started/stopped as a native service and enables auto-start at boot.

Service file: /etc/systemd/system/onprem-nginx.service

[Unit]
Description=On-Prem NGINX Docker Compose Service
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
WorkingDirectory=/on-prem
ExecStart=/usr/bin/docker-compose up -d
ExecStop=/usr/bin/docker-compose down
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

If your system uses the Compose v2 plugin use /usr/bin/docker compose up -d instead.

Reload systemd and enable the service:

sudo systemctl daemon-reload
sudo systemctl enable onprem-nginx
sudo systemctl start onprem-nginx
sudo systemctl status onprem-nginx

You should see Active: active (exited) or active (running) depending on the Type used.


7. Configure log rotation for container logs

Because logs are bind-mounted to /on-prem/logs, use logrotate to manage them.

Create /etc/logrotate.d/onprem-nginx:

/on-prem/logs/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    copytruncate
}

Notes: copytruncate is used because Docker can hold file descriptors open. Alternatively, the logging driver (like json-file) has its own rotation options.

Test logrotate configuration:

sudo logrotate -d /etc/logrotate.d/onprem-nginx

Run for real (careful):

sudo logrotate -f /etc/logrotate.d/onprem-nginx

8. Testing the service

Run these checks and capture outputs for your blog:

# Check containers
sudo docker ps

# Curl the service locally
curl http://localhost:8080

# From remote machine, use server IP
curl http://<server-ip>:8080

Expected curl output snippet:

<!DOCTYPE html>
<html>
...Hello from On-Prem NGINX Docker!

Check systemd status:

sudo systemctl status onprem-nginx

Check logs directory:

ls -la /on-prem/logs
tail -n 50 /on-prem/logs/access.log

9. Troubleshooting

systemd: status=203/EXEC — means the ExecStart points to a binary that does not exist. Fix by pointing to the correct path returned by which docker-compose or use the docker compose plugin path.

Connection refused when curling — ensure container is running (docker ps), firewall allows port 8080, and docker-compose.yml maps port 8080:80.

SSH / MobaXterm issues — verify server is up, SSH service running (sudo systemctl status ssh), and you are using correct IP/username/key.

Docker build fails — check Dockerfile syntax, network access for pulling base images, and disk space.


10. Lessons Learned

  • Always verify the path of docker-compose when using systemd to avoid status=203/EXEC errors.

  • Bind-mounting logs makes it easier to manage container logs on the host and integrate with logrotate.

  • Testing each component step-by-step prevents cascading failures and simplifies troubleshooting.

  • Using restart: always ensures high availability for on-prem deployments.

  • Systemd integration provides a native way to manage Docker Compose stacks, including auto-start on boot.


11. Conclusion & next steps

You now have a reproducible on-prem Docker deployment managed by systemd with log rotation. Next steps you might document in a follow-up post:

  • Use Docker labels or environment variables for configuration.

  • Move logs to a central logging system (ELK / Grafana).

  • Add TLS termination (Let's Encrypt or a reverse proxy).

  • Add health checks and monitoring.









Comments

Popular posts from this blog

Corporate CI/CD Pipeline

Devops Project by Using Docker Swarm, Git, GitHub, and Jenkins.

Kubernetes Deployment Strategies -Blue/Green, Canary, Rolling Updates with Yaml code