Picture of Jürgen Kreileder

Chrooting MySQL on Debian

It’s quite easy to chroot bind9 and apache on Debian. (See this page for bind9 and libapache2-mod-chroot or libapache2-mod-security for apache.)

But I’ve found no guide for chrooting MySQL, so here’s my short recipe:

  • Prepare the chroot directory. It’s recommended to use an extra partition/filesystem for it. I will use /srv/mysql (which is an LVM2 partition with an ext3 filesystem on my system) for the rest of the text.
  • Stop MySQL:
    /etc/init.d/mysql stop
  • Copy the databases to new location:
    mkdir -p /srv/mysql/var/lib
    cp -a /var/lib/mysql /srv/mysql/var/lib
  • Copy this script to /etc/default/mysql-chroot
  • Edit /etc/init.d/mysql:
    • Source the mysql-chroot script somewhere at the top:
      …
      test -x /usr/sbin/mysqld || exit 0
      
      . /etc/default/mysql-chroot
      
      SELF=$(cd $(dirname $0); pwd -P)/$(basename $0)
      …
    • Run setup_chroot right in the start section:
      …
      if mysqld_status check_alive nowarn; then
        echo "...already running."
      else
        setup_chroot
        /usr/bin/mysqld_safe > /dev/null 2>&1 &
      …
    • Somehow /var/run/mysqld/mysqld.pid disappears after each start. We have to create it each time, otherwise the stop command won’t work properly:
      …
      if mysqld_status check_alive warn; then
        echo "."
        ln -sf $CHROOT_DIR/var/run/mysqld/mysqld.pid \
                       /var/run/mysqld
        # Now start mysqlcheck or whatever the admin wants.
        /etc/mysql/debian-start
      …
  • In /etc/mysql/debian.cnf, change the socket line to:
    socket = /srv/mysql/var/run/mysqld/mysqld.sock
  • In /etc/mysql/my.cnf:
    • Change the socket line in the [client] section to:
      socket = /srv/mysql/var/run/mysqld/mysqld.sock

      Don’t change the socket lines in the other sections!

    • Add
      chroot = /srv/mysql

      to the [mysqld] section.

  • Prepend /srv/mysql to the log files listed in /etc/logrotate.d/mysql-server
  • Start MySQL:
    /etc/init.d/mysql start
  • Check /var/log/syslog for errors ;-)

March 13th, 2005: I’ve updated the script for newer Debian packages, see Updated MySQL Chroot Script for more information.

July 30th, 2006: These modifications still work fine on the current stable Debian release (3.1, “sarge”). The mysql packages in the testing (“etch”) and unstable (“sid”) distributions of Debian need a few additional changes, I’ll post an updated guide in a few days.

December 30th, 2006: I’ve made an updated guide on how to chroot more recent MySQL packages on Debian and Ubuntu

This article Jürgen Kreileder is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

16 Comments

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post. Both comments and pings are currently closed.

slink said

Hi. It’s a great tutorial. If someone would like to reach MySQL in PHP, modify php.ini too.

Chrooting Apache, MySQL und Bind unter Debian

Ein sehr schönes Tutorial stellt uns Juergen Kreileder zur Verfügung. Das Tutorial erklärt dem Nutzer, wie er unter Debian die Datenbankanwendung MySQL aus einer chroot-Umgebung starten kann. Außerdem finden sich dort zwei Links um den Apache Webse…

swiergot said

Hi. I have a problem with shutting down mysqld. Soon after mysqladmin does its work, mysqld_safe resumes mysqld process. Do you know how to fix it?

swiergot, did you change “/etc/init.d/mysql” like described above?

a_l_a_n said

I dont know if this was appropriate or not, but I had to add

ln -sf $CHROOT_DIR/var/run/mysqld/mysqld.sock /var/run/mysqld.sock

to /etc/init.d/mysql also, as amaroK was trying to use this missing socket file to connect to MySQL.

Also, I assume it was a typo, I had to change the line in the howto to:

ln -sf $CHROOT_DIR/var/run/mysqld/mysqld.pid /var/run/mysqld.pid

(Note the .pid on the end of the new symlink)

The command for the pid file is correct: It creates a link to $CHROOT_DIR/var/run/mysqld/mysqld.pid in the directory /var/run/mysqld. That means the resulting link name is /var/run/mysqld/mysqld.pid.

Creating a link for the socket is definitely an option if an application uses hard-coded paths and you can’t or don’t want to use networking (host: 127.1, port: 3306).

a_l_a_n said

Cool. Just wanted to make sure I wasnt negating the whole process or something stupid.

Thanks for the guide.

Viktor said

Hi!

I tried do as you had written above, but when I start the /etc/init.d/mysql start file, it writes: ” line 108: log_daemon_msg: command not found”.

I can not see anything suspicious in syslog file.

What can be the problem?

Thx for your response!

Viktor

Viktor, log_daemon_msg is defined in /lib/lsb/init-functions. That file should get sourced early in /etc/init.d/mysql.

amin tavana replied

Hi Juergen
After all, when i start /etc/init.d/mysql start, i have this error :
/etc/init.d/mysql: line 100: log_daemon_msg : command not found

How can i fix it?
I use Kali Linux (New Version of Backtrack)

Tnx for your response!

Amin

Josh Wilkins said

Juergen, I get the same error as viktor. I cannot figure out what it is I need to do.

-Josh

Josh, which Debian or Ubuntu distribution do you have?

Al said

Try using another DB conection file that works – It worked for me

Al said

getMessage());
}

$db_object->setFetchMode(DB_FETCHMODE_ASSOC);

// we write this later on, ignore for now.

include(‘check_login.php’);

?>

————————————————-

‘**********check_login.php**********
query(“SELECT password FROM users WHERE username = ‘”.$_SESSION[‘username’].”‘”);

if(DB::isError($pass) || $pass->numRows() != 1) {
$logged_in = 0;
unset($_SESSION[‘username’]);
unset($_SESSION[‘password’]);
// kill incorrect session variables.
}

$db_pass = $pass->fetchRow();

// now we have encrypted pass from DB in
//$db_pass[‘password’], stripslashes() just incase:

$db_pass[‘password’] = stripslashes($db_pass[‘password’]);
$_SESSION[‘password’] = stripslashes($_SESSION[‘password’]);

//compare:

if($_SESSION[‘password’] == $db_pass[‘password’]) {
// valid password for username
$logged_in = 1; // they have correct info
// in session variables.
} else {
$logged_in = 0;
unset($_SESSION[‘username’]);
unset($_SESSION[‘password’]);
// kill incorrect session variables.
}
}

// clean up
unset($db_pass[‘password’]);

$_SESSION[‘username’] = stripslashes($_SESSION[‘username’]);

?>

Al, I don’t get the context of your code excerpt.
(And I always get a bad feeling when I see code like the first line of your check_login.php. Think SQL injection.)

[…] http://blog.blackdown.de/2005/03/04/…sql-on-debian/ […]