Recently I had a task where we needed to upgrade an Apache 2.4 server running PHP 8.2 with the OCI8 extension connected to an Oracle backend. The existing setup was RPM-based on RHEL, using Remi packages, and getting OCI8 working had previously required manual handling of the Oracle Instant Client libraries.
It worked — but it was fragile.
When planning the move to PHP 8.3 (and possibly a new AlmaLinux 10 server), I started asking myself: should we really go through the same OS-bound dependency alignment again?
The Problem
The current setup required:
- Manual removal and reinstallation of
oracle-instantclient - Matching the correct
libclntsh.soversion - Updating
php82-php-oci8 - Making sure system libraries aligned with the OS version
It worked, but it wasn’t reproducible. Rebuilding this on a new server would mean repeating the same careful sequence again.
The Idea
Instead of upgrading the OS stack and PHP modules directly, I decided to containerize the setup:
php:8.3-apacheas base image- Install Oracle Instant Client inside the container
- Compile and enable OCI8 in the image
- Expose Apache on port 8083
- Restrict access using iptables to the internal network
The goal was simple:
Make the environment portable, reproducible, and independent of the host OS.
What We Did
- Built a custom Docker image with PHP 8.3 + OCI8.
- Installed Oracle Instant Client during the image build.
- Exposed the container on port 8083.
- Restricted access to
129.177.0.0/16using iptables. - Mounted the application files using a bind mount instead of copying them into the container.
The bind mount was important. Copying files into a running container works — until the container is recreated. Using a host-mounted directory ensures the application survives rebuilds.
The Result
The container is now:
- Running PHP 8.3 with OCI8
- Fully isolated from host OS library conflicts
- Easy to rebuild
- Easy to roll back
- Cleaner from an operational perspective
Most importantly: upgrading PHP in the future will now mean changing a base image tag and rebuilding — not re-engineering system libraries.
This small migration significantly reduced long-term operational risk.
FROM php:8.3-apache
# Install required system dependencies
RUN apt-get update && apt-get install -y \
libaio1t64 \
libaio-dev \
unzip \
build-essential \
&& rm -rf /var/lib/apt/lists/* \
&& ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1
# Copy Oracle Instant Client packages (download manually first)
COPY instantclient-basic-linux.x64-23.26.1.0.0.zip /tmp/
COPY instantclient-sdk-linux.x64-23.26.1.0.0.zip /tmp/
# Extract Oracle Instant Client Basic
RUN mkdir -p /opt/oracle && \
unzip -q /tmp/instantclient-basic-linux.x64-23.26.1.0.0.zip -d /opt/oracle
# Extract Oracle Instant Client SDK (force overwrite with -o)
RUN unzip -qo /tmp/instantclient-sdk-linux.x64-23.26.1.0.0.zip -d /opt/oracle
# Create symlink and cleanup
RUN ln -s /opt/oracle/instantclient_23_26 /opt/oracle/instantclient && \
rm /tmp/*.zip
# Configure library path
ENV LD_LIBRARY_PATH=/opt/oracle/instantclient
ENV ORACLE_HOME=/opt/oracle/instantclient
# Install OCI8 extension
RUN docker-php-ext-configure oci8 --with-oci8=instantclient,/opt/oracle/instantclient \
&& docker-php-ext-install oci8 \
&& docker-php-ext-enable oci8
# Enable Apache modules if needed
RUN a2enmod rewrite
RUN chown -R www-data:www-data /var/www/html
# Expose port
EXPOSE 80
