FreeBSD, PHP and Pecl
I was helping move a legacy PHP app to a new server, and found it needed a PECL extension (dbx).
After installing PEAR, I got the following error:
[root@machine php]# pecl install something
Fatal error: Call to undefined function preg_match() in /usr/local/share/pear/PEAR/Frontend/CLI.php on line 70
It turns out that the problem is that within FreeBSD’s installation of PECL, it calls PHP from the command line with the -n flag. a.k.a. —no-php-ini
This prevents /usr/local/etc/php/extensions.ini from getting loaded, and thus there is no PCRE support.
You can work around it by removing “-n” from inside the pecl script.
libmap.conf -- who knew?
It’s not often that somebody points out FreeBSD functionality that I wasn’t already aware of, but that happened today.
We were having a problem with clamav 0.90. It would slow down, stop responding, and die, somewhere in the threading code.
Craig Green, of Sentex.net, wrote us to say that he had a similar problem with a devel version of clamav on FreeBSD, and his fix was quite unexpected.
He solved his problem by forcing clamd to use a different set of threading libraries than default. (The older “libthr”, to be precise.)
He did this by using the libmap functionality that had been added to FreeBSD in 5.1 It’s incredibly simple, you just create /etc/libmap.conf, add a few lines of configuration saying what object files to substitute, and then run your app.
In this case, he suggested:
[clamd]
libc_r.so.5 libthr.so.2
libc_r.so.6 libthr.so.2
libthr.so.2 libthr.so.2
libpthread.so.1 libthr.so.2
libpthread.so.2 libthr.so.2
It worked perfectly. The application worked flawlessly with the older thread library.
So next time you want to use a non-standard library for just one application, remember that libmap.conf is your friend.
Now you know. And knowing is half the battle.
Shutting Apache Up in a FreeBSD Jail
(61)Connection refused: connect to listener on 0.0.0.0:80
(61)Connection refused: connect to listener on 0.0.0.0:80
It turns out that if you specify the Listen directive in one of the following ways:
Listen 80
Listen *:80
Listen 0.0.0.0:80
it complains about connecting to the listener as previously mentioned. To make these errors disappear from the logs, all you have to do is specify the IP address of the jail like so:
Listen jail.ip.address.here:80
and it goes away. No more error messages filling the logs.
Managing Mongrels on FreeBSD
Like a lot of other consultancies, we’re excited about Ruby on Rails. It provides a very nice framework to write clean, well-tested code in a great language. But hosting a production rails site isn’t quite as simple.
- At the bottom, we have our Ruby on Rails websites.
- They get web-enabled via Mongrel Cluster.
- And then Apache 2.2 with mod_proxy_balancer spreads the end-users hits across the hordes of mongrels.
It works well, but there are a few problems with management. Notably, there is no FreeBSD rc.d script to easily start and stop individual sites, or to automatically start them all on boot.
As such, we quickly wrote a mongrel_cluster rc.d script that accepts a few rc.conf variables, to get your mongrel cluster running on FreeBSD in no time flat.
Configuration is simple.- Make a directory (/usr/local/etc/mongrel_cluster)
- Put your mongrel_cluster yml files in that directory, naming each one for the site it represents (foo.yml bar.yml baz.yml)
- mongrel_cluster_enable=”YES”
- mongrel_cluster_dir=”/usr/local/etc/mongrel_cluster”
- mongrel_cluster_list=”foo bar baz”
And now put the attached mongrel_cluster file in your /usr/local/etc/rc.d directory.
Now you can do things like:
/usr/local/etc/rc.d/mongrel_cluster start to start all of your mongrel clusters at once.
/usr/local/etc/rc.d/mongrel_cluster stop somesite to stop “somesite” while leaving the others running.
Hopefully that makes managing your FreeBSD mongrels just a bit simpler!
Or see the whole file here:
#!/bin/sh
# PROVIDE: mongrel_cluster
# REQUIRE: DAEMON
# KEYWORD: shutdown
#
# Add the following line to /etc/rc.conf to enable mongrel_cluster:
# mongrel_cluster_enable (bool): Set to "NO" by default.
# Set it to "YES" to enable mongrel_cluster
# mongrel_cluster_list (str): Set to "" by default.
# The list of mongrel_cluster_list to start (leave off the .yml)
# mongrel_cluster_dir (str): Set to "/usr/local/etc/mongrel_clusters" by default.
#
. /etc/rc.subr
PATH=$PATH:/usr/local/bin
name="mongrel_cluster"
rcvar=`set_rcvar`
start_cmd="${name}_start"
stop_cmd="${name}_stop"
load_rc_config $name
eval "${rcvar}=\${${rcvar}:-'NO'}"
[ -z "$mongrel_cluster_list" ] && mongrel_cluster_list=""
[ -z "$mongrel_cluster_dir" ] && mongrel_cluster_dir="/usr/local/etc/mongrel_clusters"
required_dirs=$mongrel_cluster_dir
# First, let's setup our start/stop routines
mongrel_cluster_start()
{
echo "Starting Mongrel Clusters:"
for mongrel in $mongrel_cluster_list; do
echo -n " ${mongrel} -- "
/usr/local/bin/mongrel_rails cluster::start -C $mongrel_cluster_dir/$mongrel.yml
done
return 0
}
mongrel_cluster_stop()
{
echo "Stopping Mongrel Clusters:"
for mongrel in $mongrel_cluster_list; do
echo -n " $mongrel -- "
/usr/local/bin/mongrel_rails cluster::stop -C $mongrel_cluster_dir/$mongrel.yml
done
return 0
}
# everything after the start/stop is a mongrel to be started/stopped
cmd="$1"
if [ $# -gt 0 ]; then
shift
fi
if [ -n "$*" ]; then
mongrel_cluster_list="$*"
fi
run_rc_command "${cmd}"
Darcs, FreeBSD and AMD64. Happier Together.
In a previous article I wrote about a possible way to run darcs on the FreeBSD/AMD64 platform.
Sadly, it didn’t work. It nearly worked, but it did not. It’s possible the fix was simple, but I don’t know a single line of Haskell, so I didn’t bother trying.
What I did try, was the FreeBSD Linuxulator.
options COMPAT_LINUX32
and then downloaded the latest Statically linked binary for Linux/i386 from the Darcs website.
Put the darcs executable in /usr/local/bin (or wherever you prefer) then make sure FreeBSD knows what kind of executable it is by running the following:
brandelf -t Linux /usr/local/bin/darcs
Reboot and voilà! Working darcs, that seems to function not only with a small test repository, but with large, complex production repositories.
So yes, BSD-Heads, Linux is good for something after all. And yes, we are aware that this is a filthy solution, but our attempt to successfully port GHC to FreeBSD/amd64 was abandoned after it became clear that it would be very time-consuming for us, and likely very simple for somebody more familiar with the GHC build process.
Darcs, FreeBSD and AMD64. Happy Together.
Edit: This approach seemed tenable, but the resulting executable failed in some circumstances. We suggest you use the method in this article instead.
We recently moved to the AMD64 platform on FreeBSD, and for the most part it has been fantastic. The machines are screaming fast, and almost every piece of software we use has been supported.
Everything except darcs and ghc, which are i386 only on the FreeBSD platform.
We didn’t want to run a standard (dynamic) 32-bit binary, because then we would end up having to manage 32-bit version of the curl, readline and gmp libraries, in parallel with their 64-bit brothers. It seemed like a disaster waiting to happen at upgrade time.
After some experimentation, it became clear that the least bad solution would be to create a statically linked 32-bit binary, that could be run an i386 compatible kernel.
As such, first we built a new amd64 kernel with the following added to the kernel configuration:
options COMPAT_IA32
Then on an FreeBSD/i386 machine, we went about building a binary package with a statically linked binary, by making a few edits to the darcs ports Makefile. Here is the diff:
--- Makefile.orig Sat Feb 10 14:02:34 2007
+++ Makefile Sat Feb 10 14:18:44 2007
@@ -14,10 +14,10 @@
MAINTAINER= haskell@FreeBSD.org
COMMENT= Yet another replacement for CVS, written in Haskell
-BUILD_DEPENDS= ghc:${PORTSDIR}/lang/ghc
-LIB_DEPENDS= curl:${PORTSDIR}/ftp/curl \
- gmp.7:${PORTSDIR}/math/libgmp4 \
- readline.5:${PORTSDIR}/devel/readline
+BUILD_DEPENDS= ghc:${PORTSDIR}/lang/ghc \
+ curl:${PORTSDIR}/ftp/curl \
+ /usr/local/lib/libgmp.so.7:${PORTSDIR}/math/libgmp4 \
+ /usr/local/lib/libreadline.so.5:${PORTSDIR}/devel/readline
OPTIONS= SERVER "install server" off
USE_AUTOTOOLS= autoconf:259
@@ -25,6 +25,7 @@
CONFIGURE_ENV= CPPFLAGS="-I${LOCALBASE}/include ${PTHREAD_CFLAGS}" \
LDFLAGS="-L${LOCALBASE}/lib -L${PREFIX}/lib/ ${PTHREAD_LIBS}" \
CFLAGS=""
+CONFIGURE_ARGS= --with-static-libs
USE_GMAKE= yes
MAKEFILE= GNUmakefile
ALL_TARGET= darcs darcs.1
And then, still on the i386, in ports/devel/darcs, I ran make package to create a new darcs binary package, containing the statically linked binary.
This package was then able to be copied over to the amd64 machines, and installed via pkg_add, without issue.
Edit: This binary then worked fine on a test repository, but it dumped core on a large, production repository. As such we switched to a different tactic. Read about it in Part 2.