Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,21 @@ mkdir -p /var/www/html/wp-content/mu-plugins
cp -a /mu-plugins/. /var/www/html/wp-content/mu-plugins/
chmod 755 /var/www/html/wp-content/mu-plugins

# Install the SQLite Database Integration plugin and the Cloudflare D1
# database drop-in when the image bundles them and a proxy is configured.
if [ -d /wordpress-plugins/sqlite-database-integration ]; then
echo "Installing the SQLite Database Integration plugin"
rm -rf /var/www/html/wp-content/plugins/sqlite-database-integration
mkdir -p /var/www/html/wp-content/plugins
cp -a /wordpress-plugins/sqlite-database-integration /var/www/html/wp-content/plugins/

if [ -n "${WP_D1_PROXY_URL:-}" ]; then
echo "Installing the Cloudflare D1 database drop-in (wp-content/db.php)"
cp /var/www/html/wp-content/plugins/sqlite-database-integration/wp-includes/database/d1/db.copy \
/var/www/html/wp-content/db.php
chmod 644 /var/www/html/wp-content/db.php
fi
fi

# Execute the main command
exec "$@"
37 changes: 36 additions & 1 deletion flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 33 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,30 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";

# A fresh nixpkgs used only for the Rust toolchain building the native
# PHP extensions (their dependency trees need a newer cargo than the
# main pin provides).
nixpkgs-rust.url = "github:NixOS/nixpkgs/nixos-unstable";

# The SQLite Database Integration project with the Cloudflare D1 backend.
# Fetched over git (not the GitHub tarball API): the project's
# .gitattributes marks /packages as export-ignore for WordPress.org
# release exports, which would exclude it from archive downloads.
sqlite-database-integration = {
url = "git+https://github.com/Avunu/sqlite-database-integration?ref=d1-support";
flake = false;
};
};

outputs =
{ self, nixpkgs, flake-utils }:
{
self,
nixpkgs,
flake-utils,
nixpkgs-rust,
sqlite-database-integration,
}:
{
# Deploy WordPress directly on NixOS. See readme.md for usage.
nixosModules.default = import ./modules/nixos.nix;
Expand All @@ -25,12 +45,24 @@
let
pkgs = nixpkgs.legacyPackages.${system};
mkImage = php: imageName: import ./modules/containers.nix { inherit pkgs php imageName; };
mkD1Image =
php: imageName:
import ./modules/containers.nix {
inherit pkgs php imageName;
d1DriverSrc = sqlite-database-integration;
rustPkgs = nixpkgs-rust.legacyPackages.${system};
};
in
{
packages = {
wordpress-php82 = mkImage pkgs.php82 "wordpress-php82";
wordpress-php83 = mkImage pkgs.php83 "wordpress-php83";
wordpress-php84 = mkImage pkgs.php84 "wordpress-php84";
# Cloudflare D1 variants: bundle the SQLite Database Integration
# plugin, the D1 db.php drop-in, and the native wp_mysql_parser +
# wp_d1_client extensions. Configure with WP_D1_PROXY_URL.
wordpress-d1-php83 = mkD1Image pkgs.php83 "wordpress-d1-php83";
wordpress-d1-php84 = mkD1Image pkgs.php84 "wordpress-d1-php84";
default = self.packages.${system}.wordpress-php83;
};
}
Expand Down
62 changes: 62 additions & 0 deletions lib/php-extensions.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Native PHP extensions of the SQLite Database Integration project, built
# from source against the exact PHP this flake ships (ZTS, FrankenPHP-ready).
#
# - wp_mysql_parser: accelerates the MySQL lexer/parser of the SQLite
# driver (~15x parser speedup over pure PHP).
# - wp_d1_client: a native HTTP client for the Cloudflare D1 proxy
# protocol, holding a connection pool that persists across requests.
#
# Returns an attrset with the two extension derivations and `iniDir`, a
# directory with an .ini file loading both — point PHP_INI_SCAN_DIR at it
# (alongside the PHP buildEnv's own lib directory).
#
# mkPhpExtensions { pkgs; php = phpBuild; src = sqlite-database-integration; }
{
pkgs,
php,
src,
# The Rust toolchain can come from a newer package set than the PHP build.
rustPkgs ? pkgs,
}:
let
mkExtension =
{
pname,
dir,
}:
rustPkgs.rustPlatform.buildRustPackage {
inherit pname;
version = "0.1.0";
src = "${src}/packages/${dir}";
cargoLock.lockFile = "${src}/packages/${dir}/Cargo.lock";

# ext-php-rs generates bindings against the PHP headers at build time.
nativeBuildInputs = [ rustPkgs.rustPlatform.bindgenHook ];
env = {
PHP_CONFIG = "${php.unwrapped.dev}/bin/php-config";
PHP = "${php.unwrapped}/bin/php";
};

# The crates' tests require a live PHP runtime; extension correctness
# is verified by the driver test suites instead.
doCheck = false;
};

wp-mysql-parser = mkExtension {
pname = "wp_mysql_parser";
dir = "php-ext-wp-mysql-parser";
};

wp-d1-client = mkExtension {
pname = "wp_d1_client";
dir = "php-ext-wp-d1-client";
};
in
{
inherit wp-mysql-parser wp-d1-client;

iniDir = pkgs.writeTextDir "wp-native-extensions.ini" ''
extension=${wp-mysql-parser}/lib/libwp_mysql_parser.so
extension=${wp-d1-client}/lib/libwp_d1_client.so
'';
}
36 changes: 36 additions & 0 deletions modules/containers.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,33 @@
pkgs,
php,
imageName,
# Source of the SQLite Database Integration project (with the D1 backend).
# When set, the image bundles the plugin, the D1 db.php drop-in, and the
# native wp_mysql_parser + wp_d1_client extensions.
d1DriverSrc ? null,
# Package set providing the Rust toolchain for the native extensions.
rustPkgs ? pkgs,
}:
let
phpBuild = import ../lib/php.nix { inherit pkgs php; };

phpExtensions =
if d1DriverSrc == null then
null
else
import ../lib/php-extensions.nix {
inherit pkgs rustPkgs;
php = phpBuild;
src = d1DriverSrc;
};

# The PHP ini scan path: the buildEnv's own configuration, plus the native
# extensions when enabled. FrankenPHP's embedded PHP does not inherit the
# CLI wrapper's compiled-in scan directory, so it is set explicitly.
phpIniScanDir = pkgs.lib.concatStringsSep ":" (
[ "${phpBuild}/lib" ] ++ pkgs.lib.optional (phpExtensions != null) "${phpExtensions.iniDir}"
);

wp-cli = pkgs.wp-cli.override {
php = phpBuild;
};
Expand Down Expand Up @@ -42,6 +65,9 @@ pkgs.dockerTools.buildLayeredImage {
];

config = {
Env = [
"PHP_INI_SCAN_DIR=${phpIniScanDir}"
];
Entrypoint = [
"${pkgs.busybox}/bin/sh"
"${pkgs.lib.getExe docker-entrypoint}"
Expand Down Expand Up @@ -71,6 +97,16 @@ pkgs.dockerTools.buildLayeredImage {
# copy must-use plugins
mkdir mu-plugins
cp -r ${../mu-plugins}/. mu-plugins/
${
pkgs.lib.optionalString (d1DriverSrc != null) ''
# Bundle the SQLite Database Integration plugin with the D1 backend.
# The entrypoint installs it into the docroot when WP_D1_PROXY_URL is set.
# -L dereferences the plugin's wp-includes/database symlink.
mkdir -p wordpress-plugins
cp -rL ${d1DriverSrc}/packages/plugin-sqlite-database-integration wordpress-plugins/sqlite-database-integration
chmod -R u+w wordpress-plugins
''
}

# Symlink CA certificates
ln -s ${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt etc/ssl/certs/ca-certificates.crt
Expand Down
Loading