Deploying a Containerized LNMP Stack and Private Registry with Docker

Provisioning the Docker Engine on CentOS

To begin, install the necessary utilities and configure the repository for the Docker Community Edition.

# Install required utilities
yum install -y yum-utils

# Add the official Docker repository
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# Install the engine
yum install -y docker-ce

# Enable and start the service
systemctl enable docker
systemctl start docker

Configuring Image Sources

By default, containers pull images from Docker Hub. To improve download speeds in specific regions, configure a registry mirror in the daemon configuration file.

vi /etc/docker/daemon.json

Insert the following configuration, replacing the URL with a preferred accelerator endpoint:

{
  "registry-mirrors": ["https://<your-mirror-url>.mirror.aliyuncs.com"]
}

Restart the daemon to apply changes:

systemctl restart docker

Building the LNMP Environment

1. Network Configuration

Establish an isolated bridge network to allow inter-container communication.

docker network create backend_net

2. Creating the PHP Image

Create a directory for the build context and add a Dockerfile. This example compiles PHP 7.4 from source on a CentOS 7 base.

FROM centos:7
LABEL maintainer="devops@example.com"

RUN yum install -y epel-release && \
    yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
    libcurl-devel libjpeg-devel libpng-devel openssl-devel \
    libmcrypt-devel libxslt-devel libtidy-devel autoconf \
    iproute net-tools telnet wget curl && \
    yum clean all && rm -rf /var/cache/yum/*

ADD php-7.4.33.tar.gz /opt/
RUN cd /opt/php-7.4.33 && \
    ./configure --prefix=/opt/php \
    --with-config-file-path=/opt/php/etc \
    --enable-fpm --enable-opcache \
    --with-mysqli --with-pdo-mysql \
    --with-openssl --with-zlib --with-curl --with-gd \
    --enable-mbstring --enable-hash && \
    make -j 4 && make install && \
    cp php.ini-production /opt/php/etc/php.ini && \
    cp sapi/fpm/php-fpm.conf /opt/php/etc/php-fpm.conf && \
    sed -i "s/daemonize = yes/daemonize = no/" /opt/php/etc/php-fpm.conf && \
    mkdir -p /opt/php/log && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

ENV PATH $PATH:/opt/php/sbin
WORKDIR /opt/php
EXPOSE 9000
CMD ["php-fpm"]

Build the image:

docker build -t custom-php:7.4 .

3. Creating the Nginx Image

Similarly, define a Dockerfile for the web server.

FROM centos:7
LABEL maintainer="devops@example.com"

RUN yum install -y gcc gcc-c++ make \
    openssl-devel pcre-devel gd-devel \
    iproute net-tools telnet wget curl && \
    yum clean all && rm -rf /var/cache/yum/*

ADD nginx-1.20.2.tar.gz /opt/
RUN cd /opt/nginx-1.20.2 && \
    ./configure --prefix=/opt/nginx \
    --with-http_ssl_module \
    --with-http_stub_status_module && \
    make -j 4 && make install && \
    mkdir -p /opt/nginx/conf/vhost && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

ENV PATH $PATH:/opt/nginx/sbin
COPY nginx.conf /opt/nginx/conf/nginx.conf
WORKDIR /opt/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Build the image:

docker build -t custom-nginx:1.20 .

4. Orchestrating Containers

Initialize the database container with persistent storage.

docker run -d --name db_service --net backend_net \
  --mount src=db_data,dst=/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=SecurePassword123! \
  -e MYSQL_DATABASE=wordpress \
  mysql:5.7 --character-set-server=utf8

Launch the PHP processing container.

docker run -d --name app_php --net backend_net \
  --mount src=web_content,dst=/var/www/html \
  custom-php:7.4

Start the Nginx frontend, mapping port 8080 externaly.

docker run -d --name web_server --net backend_net -p 8080:80 \
  --mount src=web_content,dst=/var/www/html \
  --mount type=bind,src=$PWD/site.conf,dst=/opt/nginx/conf/vhost/site.conf \
  custom-nginx:1.20

5. Application Deployment

Verify PHP execution by creating a test file within the mounted volume.

vim /var/lib/docker/volumes/web_content/_data/index.php

Content:

<?php phpinfo(); ?>

Access http://<host-ip>:8080 to confirm functionality. To deploy WordPress, extract the archive into the shared volume.

tar -xvf wordpress-latest.tar.gz -C /var/lib/docker/volumes/web_content/_data/
mv /var/lib/docker/volumes/web_content/_data/wordpress/* /var/lib/docker/volumes/web_content/_data/

Configure wp-config.php with the database credentials defined earlier.

Setting Up Harbor Private Registry

Installation Steps

Download the offline installer and extract the contents.

tar -xvf harbor-offline-installer-v2.5.0.tgz
cd harbor

Ensure docker-compose is available in the system path.

cp docker-compose /usr/bin/
chmod +x /usr/bin/docker-compose

Prepare the configuraton file.

cp harbor.yml.tmpl harbor.yml

SSL and Configuration

Generate self-signed certificates for the registry domain.

mkdir -p /root/certs
cd /root/certs
# Execute certificate generation scripts here

Edit harbor.yml to reflect the hostname and certificate paths.

hostname: registry.local.domain
http:
  port: 8088
https:
  port: 443
  certificate: /root/certs/registry.local.domain.crt
  private_key: /root/certs/registry.local.domain.key

Run the preparation and installation scripts.

./prepare
./install.sh

Client Configuration

Add the registry hostname to the local hosts file.

echo "<host-ip> registry.local.domain" >> /etc/hosts

Distribute the CA certificate to clients to avoid TLS errors.

scp /root/certs/registry.local.domain.crt <client-ip>:/etc/docker/certs.d/registry.local.domain/ca.crt

Usage

Authenticate with the private registry.

docker login registry.local.domain
# Username: admin
# Password: Harbor12345

Tag and push an image.

docker tag busybox:latest registry.local.domain/library/busybox:v1
docker push registry.local.domain/library/busybox:v1

Harbor stores data in /data and logs can be reviewed at /var/log/harbor/.

Tags: docker LNMP harbor containerization Linux

Posted on Wed, 05 Aug 2026 16:51:27 +0000 by PDP11