Build a docker image with nginx+php+app using dockerTools.buildImage

Goal: Build a docker image with nginx, php, and the source code of my application, using dockerTools.buildImage. This is what I have so far:

php-app-source.nix:

{ pkgs ? import <nixpkgs> {} }:

with pkgs;

{
  source-code = stdenv.mkDerivation {
    name = "app-source";

    src = ./php-app;

    phases = [ "installPhase" ];
    installPhase = ''
      mkdir -p $out
      cp -r $src $out/app
    '';
  };
}

docker-image.nix:

{ pkgs ? import <nixpkgs> {} }:

with pkgs;

let
  source = import ./php-app-source.nix { inherit pkgs; };
  nginxPort = "80";
  nginxConf = pkgs.writeText "nginx.conf" ''
    user nginx nginx;
    daemon off;
    error_log /dev/stdout info;
    pid /dev/null;
    events {}
    http {
      access_log /dev/stdout;
      server {
        listen ${nginxPort};
        index index.html;
        location / {
          root ${nginxWebRoot};
        }
      }
    }
  '';
  nginxWebRoot = pkgs.writeTextDir "index.html" ''
    <html><body><h1>Hello from NGINX</h1></body></html>
  '';
in
  dockerTools.buildImage {
    name = "my-app";
    tag = "test";
    contents = [
      bashInteractive
      busybox
      nginx
      php
      source.source-code
    ];

    runAsRoot = ''
      #!${stdenv.shell}
      ${dockerTools.shadowSetup}
      groupadd --system nginx
      useradd --system --gid nginx nginx
    '';

    extraCommands = ''
      # nginx still tries to read this directory even if error_log
      # directive is specifying another file :/
      mkdir -p var/log/nginx
      mkdir -p var/cache/nginx
    '';

    config = {
      Cmd = [ "nginx" "-c" nginxConf ];
      ExposedPorts = {
        "${nginxPort}/tcp" = {};
      };
    };

  }

Here’s how I build the image and run a container:

nix-build docker-image.nix && \
  docker load < ./result && \
  docker run -it -p 8000:80 my-app:test

This runs a docker container with nginx. http://localhost:8000 works and shows “Hello from NGINX”. What I need some pointers for now is how I can/should setup nginx to use php, and how to configure php-fpm. I’ve tried googling for “nix buildimage php nginx” and similar but I haven’t found any examples with this. I previously got help with setting this up directly on a VPS (not using docker): https://discourse.nixos.org/t/tutorial-for-setting-up-the-lamp-stack-on-a-nixos-server/12508. I haven’t been able to extract from that and get it working with buildImage.

Thanks for taking the time to read this.

Hello,

Have you found out a solution for this?

Thanks.

Here’s a working example:

With nginx
packages = let
  src = ./.;
  php = pkgs.php81;
in {
  app = php.buildComposerProject {
    inherit src;

    pname = "app-demo";
    version = "1.0.0";

    vendorHash = "sha256-SrE51k3nC5idaDHNxiNM7NIbIERIf8abrCzFEdxOQWA=";
  };

  oci-image = let
    nginxPort = "8000";
    nginxWebRoot = "${self'.packages.app}/share/php/app-demo/public";

    nginxConf = pkgs.writeText "nginx.conf" ''
      user nobody nobody;
      daemon off;
      error_log /dev/stdout info;
      pid /dev/null;
      events {}
      http {
        access_log /dev/stdout;
        server {
          listen ${nginxPort};
          index index.php index.html;
          charset utf-8;

          add_header X-Frame-Options "SAMEORIGIN";
          add_header X-Content-Type-Options "nosniff";
          location / {
            root ${nginxWebRoot};
            try_files $uri $uri/ /index.php?$query_string;
          }
          location ~ \.php$ {
            root ${nginxWebRoot};
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            include ${pkgs.nginx}/conf/fastcgi_params;
            include ${pkgs.nginx}/conf/fastcgi.conf;
          }
        }
      }
    '';
  in
  pkgs.dockerTools.buildLayeredImage {
    name = self'.packages.app.pname;
    tag = "latest";

    contents = [
      php
      pkgs.nginx
      pkgs.fakeNss
      (pkgs.writeScriptBin "start-server" ''
        #!${pkgs.runtimeShell}
        php-fpm -y /etc/php-fpm.d/www.conf.default & nginx -c ${nginxConf};
      '')
    ];

    extraCommands = ''
      mkdir -p var/log/nginx
      mkdir -p var/cache/nginx
      mkdir -p tmp
      chmod 1777 tmp
    '';

    config = {
      Cmd = [ "start-server" ];
      ExposedPorts = {
        "${nginxPort}/tcp" = {};
      };
    };
  };
};
With caddy
packages = let
          src = ./.;
          php = pkgs.php1;
in {
  app = php.buildComposerProject {
    inherit src;

    pname = "app-demo";
    version = "1.0.0";

    vendorHash = "sha256-SrE51k3nC5idaDHNxiNM7NIbIERIf8abrCzFEdxOQWA=";
  };

  oci-image = let
    webport = "8000";
    webroot = "${self'.packages.app}/share/php/app-demo/public";

    caddyFile = pkgs.writeText "Caddyfile" ''
    :${webport}
    root * ${webroot}
    log
    encode gzip
    php_fastcgi 127.0.0.1:9000
    file_server
    '';
  in
  pkgs.dockerTools.buildLayeredImage {
    name = self'.packages.app.pname;
    tag = "latest";

    contents = [
      php
      pkgs.caddy
      pkgs.fakeNss
      (pkgs.writeScriptBin "start-server" ''
        #!${pkgs.runtimeShell}
        php-fpm -D -y /etc/php-fpm.d/www.conf.default
        caddy run --adapter caddyfile --config ${caddyFile}
      '')
    ];

    extraCommands = ''
      mkdir -p tmp
      chmod 1777 tmp
    '';

    config = {
      Cmd = [ "start-server" ];
      ExposedPorts = {
        "${webport}/tcp" = {};
      };
    };
  };
};

Added on the wiki: PHP - NixOS Wiki

1 Like