How to run phpMyAdmin?


#1

Anyone has a NixOS configuration for running phpMyAdmin that he/she could share?

There are at least two components here that I’m not familiar with: hosting PHP applications and running phpMyAdmin, so I hope to lean on someone’s experience instead of discovering everything by myself…


#2

I have professional expereance with hosting PHP applications. I worked the last 5 years as admin at a small hosting company.

A good setup to host PHP in production is PHP-FPM. Have a linux user for every application and a FPM pool, so when one application is hacked, the data from the other is safe. (Keep software updated, so the chance to get hacked is drastically reduced!)
Using a unix socket might be slightly more performant than bind to local TCP port like 127.0.0.1:8000. It helps also to not reach the limit of open TCP connections for high traffic sites. But TCP is also OK, not much difference practically.

Here is the config of my NixOS VPS hosting some PHP applications: https://github.com/davidak/nixos-config/blob/13642818b0e6f3c9587b58627aa110f604b672a3/machines/atomic/configuration.nix#L141-L219

I use the Caddy webserver. It has good performance, automatic HTTPS using Let’s encrypt! and is very easy to configure. You might want to use Nginx for a common, high performance webserver or Apache, if you need support for site configuration using .htaccess file. Search for PHP-FPM config for the webserver you want to use.

phpMyAdmin is just a normal PHP application. It should be no problem to install and configure it using the provided documentation.

A simpler way to manage a database is Adminer. It’s just one PHP file you put in your webspace. That’s it. I used it a lot when i just want to do something quickly without proper setup of phpMyAdmin.

I hope that helps. Feel free to ask if anything is still unclear.


#3

Thanks for the explanation and the configuration.

Do you mean installing it in an imperative way? I hoped for a declarative configuration. :slight_smile:

Also, I don’t understand where you keep the PHP applications themselves, given your configuration. Are they just placed in /var/www/${user}? Does the web server know to map the PHP application’s URL to /var/www/${user} and invoke PHP-FPM with the resulting path?

Also, thanks for referencing Adminer, I’ll take a look, it could be appropriate for my needs.


#4

Do you mean installing it in an imperative way? I hoped for a declarative configuration. :slight_smile:

Yes. i havn’t found a NixOS module or package for it. You could create one, but that will probably take some time.

So a quick solution is just put the PHP files in your webroot.

Also, I don’t understand where you keep the PHP applications themselves, given your configuration.

Yes, i import additional webserver configs for the sites: https://github.com/davidak/nixos-config/blob/13642818b0e6f3c9587b58627aa110f604b672a3/machines/atomic/configuration.nix#L227

The Webroot is in /var/www/${user}/web. The webserver config says that every .php file is passed to PHP-FPM.

Here is a different host that uses Nginx: https://github.com/davidak/nixos-config/blob/02f09fafaa306aff83e61b7d36fcc1dc0fb476bf/machines/web/configuration.nix#L166-L171


#5

Not shure if this is all idiomatic nix, but this is my take on declaratively deploying a php application like phpmyadmin:

pkg.nix

{ stdenv, fetchurl, configFile }:
stdenv.mkDerivation rec {
  name = "phpmyadmin-${version}";
  version = "4.7.2";

  src = fetchurl {
    url = "https://files.phpmyadmin.net/phpMyAdmin/${version}/phpMyAdmin-${version}-all-languages.tar.gz";
    sha256 = "53bad6e63998732db704be45f1ea106cf26be23cf025922e5b2249e7709abc4f";
  };

  phases = [
    "unpackPhase"
    "installPhase"
  ];

  installPhase = 
  ''
    mkdir -p $out
    cp -r * $out/
    ln -s ${configFile} $out/config.inc.php
  '';

  meta = {
    homepage = https://www.phpmyadmin.net/;
    description = "phpMyAdmin is a free and open source administration tool for MySQL and MariaDB";
  };
}

module.nix

{pkgs, lib, ...}:
{
  services.httpd =
  {
    enable = true;
    enablePHP = true;
    adminAddr = "admin@email.tld";

    extraConfig = ''
      DirectoryIndex index.html index.php
    '';

    virtualHosts = 
    let
    configFile = pkgs.writeText "config.inc.php" ''
      <?php
      /* Authentication type */
      $cfg['Servers'][1]['auth_type'] = 'http';
      /* Server parameters */
      $cfg['Servers'][1]['host'] = 'localhost';
      $cfg['Servers'][1]['compress'] = false;
      $cfg['Servers'][1]['AllowNoPassword'] = false;
    '';
    phpmyadminPkg = pkgs.callPackage ./pkg.nix { inherit configFile; };
    phpmyadmin = {
      hostName = "phpmyadmin.tld";
      documentRoot = phpmyadminPkg;
      extraConfig = ''
        <Directory "${phpmyadminPkg}">
          Options -Indexes
        </Directory>
      '';
    };   
   in [phpmyadmin];
  };
}

#6

The config should not be included in the package. Maybe it can get included in PHP somehow. But i don’t know what the best way is to do that on NixOS.
Also the credentials are readable for every user on the system in the nix store. A workaround is to create a file for that manually like here https://github.com/NixOS/nixpkgs/blob/eb1afe452af8a04cfbc98ceb60acb2f92553af68/nixos/modules/services/backup/restic.nix#L134-L135.

I also don’t know if a solution is found to support different webservers. Many modules use Nginx, some Apache, what if i already use a different one?

You can create a Pull Request for nixpkgs and ask for feedback there. This would be very usefull to have packaged.


#7

Well i think this approach is far better than imperatively copying some .php files to some mutable web root like you suggested.
Often times php apps require the configuration file inside their web root. In these cases i think it can be accepted that building the package with a different configuration takes up some harddisk space.

I don’t see any credentials in my example. It was intentionally left simple ($cfg['Servers'][1]['auth_type'] = 'http'; means you authenticate directly with your mysql credentials via http basic auth).
But you could probably include a php file with restrictive permissions (like from the nixops keys service: https://nixos.org/nixops/manual/#idm140737318276736) from inside config.inc.php or pass in credentials via the environment like in restic.nix.

My module is just to provide a (working) example of how to do it with some web server. In my case this was apache. I don’t think it would be hard to adapt it to nginx or caddy.
The principle is always the same: set the web root to the store path of your app: this way you have an immutable web root, which in itself is a nice security bonus.


#8

@thorstenweber83 Thanks, this is indeed not too idiomatic because of making the configuration a parameter of the package, but it can get things working without relying on imperative installation.

I’m thinking about creating proper package+module for phpMyAdmin. My plan is to create a mutable directory with symlinks to all files and directories of phpMyAdmin in Nix store, and the configuration file being the only regular file. (I suspect this may not work because the Web application will resolve the symlinks and try to find the configuration in the wrong place.) I need to keep the configuration file away from the Nix store because I want it to store the MySQL logins.

Regarding Web server support: the module for Matomo, for example, runs it in PHP-FPM, offers integration with nginx, but allows using a different front-end Web server with fastcgi support (which will need to be configured manually). This looks like a sound approach.


#9

Of course, this would be done by the module code, not manually.


#10

Using php-fpm sounds good!
I think you probably also could pass your secrets to your php-fpm pool’s systemd unit via the environment file:

systemd.services.phpfpm-phpmyadmin.serviceConfig.EnvironmentFile = "/path/to/your/secrets-file";

and then in your pool’s config forward them to the php environment:

env[SECRET] = $SECRET

so you can finally in your configuration file get your secret like this:

getenv('SECRET')

phpmyadmin also reads some environment variables for configuration by itself:

https://docs.phpmyadmin.net/en/latest/setup.html#docker-environment-variables