Enabling Face Recognition on Nextcloud Docker

I enabled Face Recognition on Nextcloud Docker by modifying an official Docker image and integrating it into my anton-apps repository. Overcame challenges, including reverse proxy timeouts, to keep my homelab setup portable, efficient, and fully functional.

Enabling Face Recognition on Nextcloud Docker

In my homelab, I rely exclusively on Docker to run all applications. This approach ensures that my setup remains portable, self-recovering, and easily replicable in case of migration. However, using Docker sometimes introduces limitations with certain applications, particularly when specific dependencies are not readily available. One such challenge arose when I tried to enable the Face Recognition app on my Docker-based Nextcloud instance.

The Challenge

The Face Recognition app on Nextcloud requires several dependencies that are not straightforward to implement within a Docker container. My search for a solution led me to this GitHub issue thread, where other users were grappling with the same problem. Unfortunately, there wasn’t an official solution at the time, and the custom setups shared by users in the thread didn’t fully meet my needs. I prefer using authoritative sources and the latest versions to maintain the integrity and security of my homelab.

The Solution

Luckily, I discovered a Docker reference in the official Face Recognition repository: FaceRecognition Docker Wiki. While this Docker image provided a good starting point, it wasn’t flawless. I encountered some issues that required modifications.

To address these problems, I made the necessary adjustments to the Dockerfile and included the updated image in my anton-apps repository, specifically within the Nextcloud service.

#
# Use a temporary image to compile and test the libraries
#
FROM nextcloud:29.0.0-apache as builder
# Build and install dlib on builder
#
RUN apt-get update ; \
    apt-get install -y build-essential wget cmake libx11-dev libopenblas-dev

ARG DLIB_BRANCH=v19.19
RUN wget -c -q https://github.com/davisking/dlib/archive/$DLIB_BRANCH.tar.gz \
    && tar xf $DLIB_BRANCH.tar.gz \
    && mv dlib-* dlib \
    && cd dlib/dlib \
    && mkdir build \
    && cmake -S .. -B build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release \
    && cd build \
    && make \
    && make install

# Build and install PDLib on builder
ARG PDLIB_BRANCH=master
RUN apt-get install unzip
RUN wget -c -q https://github.com/matiasdelellis/pdlib/archive/$PDLIB_BRANCH.zip \
    && unzip $PDLIB_BRANCH \
    && mv pdlib-* pdlib \
    && cd pdlib \
    && phpize \
    && ./configure \
    && make \
    && make install

# Enable PDlib on builder

# If necesary take the php settings folder uncommenting the next line
# RUN php -i | grep "Scan this dir for additional .ini files"
RUN echo "extension=pdlib.so" > /usr/local/etc/php/conf.d/pdlib.ini

# Install bzip2 needed to extract models

RUN apt-get install -y libbz2-dev
RUN docker-php-ext-install bz2

# Test PDlib instalation on builder

RUN apt-get install -y git
RUN git clone https://github.com/matiasdelellis/pdlib-min-test-suite.git \
    && cd pdlib-min-test-suite \
    && make

#
# If pass the tests, we are able to create the final image.
#
FROM nextcloud:29.0.0-apache

# Install dependencies to image

RUN apt-get update ; \
    apt-get install -y libopenblas-dev

# Install dlib and PDlib to image

COPY --from=builder /usr/local/lib/libdlib.so* /usr/local/lib/

# If is necesary take the php extention folder (/usr/local/lib/php/extensions/no-debug-non-zts-20180731) uncommenting the next line
# RUN php -i | grep extension_dir
COPY --from=builder /usr/local/lib/php/extensions/no-debug-non-zts-20220829/pdlib.so /usr/local/lib/php/extensions/no-debug-non-zts-20220829/

# Enable PDlib on final image
RUN echo "extension=pdlib.so" > /usr/local/etc/php/conf.d/pdlib.ini

# Increse memory limits
RUN echo memory_limit=1024M > /usr/local/etc/php/conf.d/memory-limit.ini

# Pdlib is already installed now on final image without all build dependencies.
# You could test again if everything is correct, uncommenting the next lines.
#
# RUN apt-get install -y git wget
# RUN git clone https://github.com/matiasdelellis/pdlib-min-test-suite.git \
#    && cd pdlib-min-test-suite \
#    && make

#
# At this point you meet all the dependencies to install the application
# You can skip this step and install the application from the application store
#
ARG FR_BRANCH=master
ENV PHP_MEMORY_LIMIT=2048M
RUN apt-get install -y wget unzip nodejs npm
RUN wget -c -q -O facerecognition https://github.com/matiasdelellis/facerecognition/archive/$FR_BRANCH.zip \
  && unzip facerecognition \
  && mv facerecognition-*  /usr/src/nextcloud/facerecognition \
  && cd /usr/src/nextcloud/facerecognition \
  && sed -i 's/webpack --node-env production/NODE_ENV=production webpack/g' package.json \
  && sed -i 's/webpack --node-env development/NODE_ENV=development webpack/g' package.json \
  && npm ci \
  && make

Implementation

The modified Dockerfile is configured within the associated docker-compose.yml file. When I run docker-compose up -d, it automatically builds the image and spins up the container. This approach keeps the build process efficient, as Docker recognizes changes in the Dockerfile—such as updates to the Nextcloud base image—and rebuilds the image accordingly.

services:
  nextcloud:
    build:
      context: .
      dockerfile: Dockerfile
    image: nextcloud-mrishab:29.0.0-apache
    container_name: nextcloud
    restart: unless-stopped
    ports:
      - ${NC_PORT}:80
    environment:
      OVERWRITEPROTOCOL: https
    volumes:
      - ${NC_MOUNT_DIR}:/var/www/html

Running the Face Recognition Job

After successfully enabling the Face Recognition app, I executed the background job to perform clustering on my existing 100,000 photos. This process took about five days to complete. However, after the job was done, I started encountering issues due to request timeouts. Initially, I suspected it was an issue with Nextcloud itself.

Fortunately, I identified the root cause as a timeout setting in my reverse proxy configuration. By adjusting the timeout limit in my anton-reverse-proxy, I resolved the issue. The fix was implemented through this commit, which increased the proxy timeout to accommodate the longer processing time required by the Face Recognition app.


Conclusion

Enabling Face Recognition on Nextcloud Docker was a challenging but rewarding process. By leveraging Docker’s flexibility and making targeted modifications, I was able to integrate this powerful feature into my homelab. The experience reinforced the importance of maintaining control over your setup and being willing to dive into the details when necessary. As always, my goal is to keep my setup secure, efficient, and fully portable—principles that I believe are key to any successful homelab.