Installing FreeGhost under Debian
For those sysadmin's like myself condemed to installing dire and crappy software, these instructions are for you. FreeGhost is some ghastly PHP spaghetti-logic-driven abortion thing that attempts to do everything and anything...none of it well. I had two options, support FreeGhost or Norton Ghost, alas eating my own feces was not given as a third option, so I lumped for FreeGhost. After some other projects are out the way, I will put something together that will solve this opensource mess of imaging solutions and give us all something usable.
The instructions here are effectively complete, however some more ACL work needs to be done at some stage, if I can be bothered. The effort, in my honest opinion, would be better spent on actually putting together a good imaging solution.
As a sysadmin fighting the good fight, there are a few things you need to be aware of that you might have not picked up which makes FreeGhost particularly 'fruity' to live with:
- multiple imagings at once are multicasted on the same group address but just using different port numbers
the idea that it has to be your master TFTP server and is keen to be your DHCP server raises eyebrows, fortunately this can be tammed
- there is no 'authentication' for imaging a PC...anyone can come along and install one of your VLKM Windows images on any kit...great!
- NFS being globally writable makes it interesting so that people could upload dubious images
- a mysql database, to connect to as root eh...any ACL's in there at all, you guessed it...no
so, a seperate NFS, TFTP and FTP services? TFTP is obviously justifiable, however yes the FreeGhost team did it again and pointless added FTP and NFS to the mix, when they could have just used udpcast, or hell even tftp. "All hail FreeGhost and their wisdom..."
- PHP uploading by up'ing the HTTP POST limit to 2GB
- they reinvented cron :-/
seems the authors cannot comprehend that with DHCP you have a lease time, this means you cannot just grab a lease and assume till the end of time that the lease is going to be valid. This is not straight forward and I cannot really be bothered to fix this, so here is a warning to poor sysadmins who want to have short lease times (less than one hour) for workstations being imaged...you cannot. This really causes problems for those of us who use DHCP snooping and ARP inspection, this braindeadness gets in the way
for some reason, they think you need to get Apache to fork a call to 'sudo' to fire off wakeonlan. This is terrible, it is actually worse than terrible, it is a braindead move. My patch below to get around this pure idiocracy simply calls an executable that fires off the desired UDP packet (and permits multiple WoL destinations)...this is still bad as the whole thing can be implemented just in pure PHP, however the less time I spend with FreeGhost, the better I have found it to be for my sanity
- [insert here countless other "dear god no" moments as I come across them]
So, on with the 'fun'...if you dare.
Dependencies
- apache2-mpm-worker
- libapache2-mod-fcgid
- mysql-server
- tftpd-hpa
udpcast - from the udpcast website though, not the regular Debian one as it's too old
- vsftpd
- unfsd3 - (you can use nfs-kernel-server, however /images for us is an NFS mount, so to re-export it you need a userland NFS server)
- wakeonlan
- php5-cgi
- php5-cli
- php5-mysql
- php5-curl
- php5-gd
- cronolog
- acl
- htmldoc
- libcrypt-passwdmd5-perl
PXE Booting
We assume you have a central DHCP server and also are keen on PXE booting generally for other purposes, so the whole FreeGhost approach probably disgusts you. Fortunately we have worked out how to do things far more neatly.
Assuming you are using ISC DHCPd, you will need something like the following in your configuration. The IP 10.0.0.1, obviously amend to your needs, points to your master PXE booting server and not your FreeGhost box:
class "pxe" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
default-lease-time 300;
max-lease-time 600;
next-server 10.0.0.1;
filename "pxelinux.0";
}We use pxelinux here at SOAS 1 and you can configure pxelinux to only fire up a menu if the 'Alt' key is pressed; I like to think 'Alt' for 'Alternative'. So you can have it default to booting to the FreeGhost TFTP server, using pxechain.cbt (see later), however if you use the alternative boot approach, you get your interactive menu. Win!
# give us a prompt (if zero only when Shift, Alt, CapsLock or ScrollLock is pressed) PROMPT 0 # prompt lives for centiseconds TIMEOUT 1 TOTALTIMEOUT 1 ONTIMEOUT menu # no user tweaking of the boot options ALLOWOPTIONS 0 NOESCAPE 0 # Default boot option to use DEFAULT fog # Menus LABEL local LOCALBOOT 0 # 1.2.3.4 is the IP of the FreeGhost box LABEL fog COMBOOT /pxelinux.cfg/pxechain.com APPEND 1.2.3.4::pxelinux.0 LABEL menu CONFIG /pxelinux.cfg/default-menu
As you probably have worked out, default-menu is your interactive PXE menu setup. Enjoy.
pxechain.com
This used to involve a patch however fortunately it is now in the main syslinux source tree.
Something on our TODO list is to add failure support to the COM module so that if it fails to chain boot to the next PXE server it will automagically boot straight off the localhost's harddisk. If you want to do the work, then please do and let us have the changes.
Installing
Base Install
$ cd /usr/src
$ wget http://.../fog_0.28.tar.gz
$ tar zxf fog_0.28.tar.gz
# # we actually have 256M for 'fog', then 10G for 'snapins' as a separate LVM
# lvcreate -L 10G -n fog lvm-hostname
# mkfs.xfs -L fog /dev/lvm-hostname/fog
# echo "LABEL=fog /opt/fog xfs relatime,nodev,nosuid,noexec 0 10" >> /etc/fstab
# mkdir /opt/fog
# mount /opt/fog
# chown root:root -R /opt/fog/
# mkdir /opt/fog/{log,snapins}
# chown -R www-data:staff /opt/fog/{log,snapins}
# cp -a /usr/src/fog_0.28/packages/utils /opt/fog/
# chown -R root:staff /opt/fog/utils
# useradd -s /bin/false -d /opt/fog fog
# cp -a /usr/src/fog_0.28/packages/tftp /opt/fog
# setfacl -R -m u:ftp:rwx /opt/fog/tftp/fog /opt/fog/tftp/pxelinux.cfg
# mkdir -p /opt/fog/images/dev
# ln -s /opt/fog/images /images
# chmod g+s /opt/fog/images
# setfacl -m u:ftp:wx /opt/fog/images
# chmod 777 /opt/fog/images/dev
# touch /opt/fog/images/.mntcheck
# touch /opt/fog/images/dev/.mntcheck
# cp -a /usr/src/fog_0.28/packages/web /opt/fog/
# wget http://www.fogproject.org/images/favicon.ico -O /opt/fog/web/favicon.ico
# echo -e "User-agent: *\nDisallow: /" > /opt/fog/web/robots.txt
# cp -a /usr/src/fog_0.28/packages/service /opt/fog/
# chown -R root:staff /opt/fog/web /opt/fog/services
# find /opt/fog/web -type d -exec chmod 755 '{}' \;
# find /opt/fog/web -type f -exec chmod 644 '{}' \;
# find /opt/fog/web -type f -iregex '.*\.php' -exec chmod +x '{}' \;Now apply the patch fog-wol-fix.diff.
Web Service
$ cat /etc/apache2/sites-available/fog
<VirtualHost *:80>
ServerName fog.example.com
# ewwwwwwwwwww, we need to put in the IP address of the FOG server here for task pickups :-/
ServerAlias 1.2.3.4
ServerAdmin sysadmin@example.com
DocumentRoot /opt/fog/web/
DirectoryIndex index.html index.php
# removes the ajax and other pointless guff from the logs
# N.B. only works from inside a <Virtualhost/> element
<IfModule mod_setenvif.c>
SetEnvIf Request_URI "/favicon.ico$" dontlog
SetEnvIf Request_URI "/status/(bandwidth|freespace)\.php$" dontlog
SetEnvIf Request_URI "/service/[^/]+\.php$" dontlog
SetEnvIF Request_URI "/management/ajax/activetasks.php$" dontlog
SetEnvIf Request_URI "/management/phpimages/bandwidth\.(update|phpgraph)\.php$" dontlog
SetEnvIf Request_URI "/management/phpimages/30day\.phpgraph\.php$" dontlog
CustomLog "|exec /usr/bin/cronolog -S /opt/fog/log/access.log /opt/fog/log/access-%Y%U.log" common env=!dontlog
</IfModule>
<IfModule !mod_setenvif.c>
CustomLog "|exec /usr/bin/cronolog -S /opt/fog/log/access.log /opt/fog/log/access-%Y%U.log" common
</IfModule>
ErrorLog "|exec /usr/bin/cronolog -S /opt/fog/log/error.log /opt/fog/log/error-%Y%U.log"
# muppets cannot live without hardcoding '/fog/' everywhere :-/
Alias /fog/ /opt/fog/web/
<Directory /opt/fog/web/>
Options -All
<IfModule mod_fcgid.c>
<Files *.php>
Options +ExecCGI
SetHandler fcgid-script
FCGIWrapper /usr/bin/php-cgi .php
</Files>
</IfModule>
</Directory>
# # Handy (optional) LDAP frontend to things
# # I recommend you SSL (only /management and /mobile), with a well placed RedirectMatch
# <Location />
# AuthName "FreeGhost"
# AuthType Basic
# AuthBasicProvider ldap
#
# AuthLDAPURL ldap://ldap1.example.com/ou=Users,dc=example,dc=com?cn?sub?(&(objectClass=Person)(|(!(loginDisabled=*))(loginDisabled=FALSE))) STARTTLS
# AuthLDAPURL ldap://ldap2.example.com/ou=Users,dc=example,dc=com?cn?sub?(&(objectClass=Person)(|(!(loginDisabled=*))(loginDisabled=FALSE))) STARTTLS
#
# AuthzLDAPAuthoritative Off
# </Location>
# <Location /management/>
# require ldap-group cn=fog-admin,ou=Groups,dc=example,dc=com
#
# Order Allow,Deny
# Allow From 192.168.0.0/16
# Allow From 172.16.0.0/12
# Allow From 10.0.0.0/8
# #Allow From All
# </Location>
# <Location /mobile/>
# require ldap-group cn=fog-user,ou=Groups,dc=example,dc=com
# </Location>
</VirtualHost>cat /opt/fog/web/commons/config.php
[snipped]
// real wol support, send the packets to 1.2.3.255 and 1.2.4.255, for example
//define( "FOG_WOL_ADDRESSES", serialize(array('1.2.3.255', '1.2.4.255')) );
define( "MYSQL_HOST", "localhost" );
define( "MYSQL_DATABASE", "fog" );
define( "MYSQL_USERNAME", "root" );
define( "MYSQL_PASSWORD", "whatever here is your password" );
[snipped]Now go to http://fog.example.com/ and login (user: fog, pass: password) and go straight to the 'FOG Settings' section under the information section of the managment panel; lurking under the info 'i' button, second from the far right hand side. Change the settings so that the hostnames are all 'fog.example.com' and keep an eye on FOG_SERVICE_AUTOLOGOFF_BGIMAGE as it keeps adding \'s all the time. You might want to also amend your network interface to 'bond0' if you are being cunning and using link aggregation to get better performance.
You also need to amend the FTP/TFTP bits:
FOG_TFTP_HOST: |
127.0.0.1 |
FOG_TFTP_FTP_USERNAME: |
anonymous |
FOG_TFTP_FTP_PASSWORD: |
{empty} |
FOG_TFTP_PXE_CONFIG_DIR: |
tftp/pxelinux.cfg/ |
FOG_PXE_IMAGE_DNSADDRESS: |
{ip address of primary dns server} |
You need to also amend the 'Storage Node' so that the default (and only one):
Management Username: |
anonymous |
Management Password: |
{empty} |
Supporting Services
Now edit /opt/fog/service/etc/config.php to update the following:
// yes, that's *UPD*.... :-/ define( "UPDSENDERPATH", "/usr/sbin/udp-sender" ); define( "MULTICASTLOGPATH", "/opt/fog/log/multicast.log" ); define( "MULTICASTDEVICEOUTPUT", "/dev/tty6" ); define( "MULTICASTSLEEPTIME", 10 ); define( "MULTICASTINTERFACE", "bond0" ); define( "UDPSENDER_MAXWAIT", null ); define( "MYSQL_HOST", "localhost" ); define( "MYSQL_DATABASE", "fog" ); define( "MYSQL_USERNAME", "root" ); define( "MYSQL_PASSWORD", "whatever you would normally use here" ); define( "LOGMAXSIZE", "1000000" ); define( "REPLICATORLOGPATH", "/opt/fog/log/fogreplicator.log" ); define( "REPLICATORDEVICEOUTPUT", "/dev/tty7" ); define( "REPLICATORSLEEPTIME", 600 ); //600 define( "REPLICATORIFCONFIG", "/sbin/ifconfig" ); define( "SCHEDULERLOGPATH", "/opt/fog/log/fogscheduler.log" ); define( "SCHEDULERDEVICEOUTPUT", "/dev/tty8" ); define( "SCHEDULERWEBROOT", "/opt/fog/web" ); define( "SCHEDULERSLEEPTIME", 60 );
Now edit your /etc/exports file to show:
# for nfs-kernel-server #/images *(ro,no_subtree_check,sync,no_wdelay,no_root_squash,insecure,insecure_locks) #/images/dev *(rw,no_subtree_check,sync,no_wdelay,no_root_squash,insecure) # for unfsd3 /images (ro,insecure,no_root_squash) /images/dev (rw,insecure,no_root_squash)
# cp /usr/src/fog_0.28/packages/init.d/ubuntu/FOG* /etc/init.d/ # chown root:root /etc/init.d/FOG* # chmod +x /etc/init.d/FOG* # update-rc.d FOGMulticastManager defaults # update-rc.d FOGImageReplicator defaults # update-rc.d FOGScheduler defaults # /etc/init.d/FOGMulticastManager start # /etc/init.d/FOGImageReplicator start # /etc/init.d/FOGScheduler start
Depending on whether you have switches or hubs in your network, you might want to change the two seperate 'udp-sender' calls to not use '--half-duplex' but instead '--full-duplex' in '/opt/fog/service/common/lib/MulticastTask.class.php' too. Now start both those services.
Now to configure the FTP service:
# grep -v "^#" /etc/vsftpd.conf listen=YES tcp_wrappers=YES chown_username=fog anon_upload_enable=YES anon_umask=022 delete_failed_uploads=YES anon_other_write_enable=YES anon_root=/opt/fog anonymous_enable=YES write_enable=YES local_umask=022 dirmessage_enable=YES xferlog_enable=YES connect_from_port_20=YES xferlog_std_format=YES secure_chroot_dir=/var/run/vsftpd pam_service_name=vsftpd rsa_cert_file=/etc/ssl/certs/vsftpd.pem # echo "vsftpd: ALL" >> /etc/hosts.deny # echo "vsftpd: localhost 1.2.3.4" >> /etc/hosts.allow # /etc/init.d/vsftpd restart
Now edit '/etc/default/tftpd-hpa' to be:
# cat /etc/default/tftpd-hpa RUN_DAEMON="yes" OPTIONS="-l -v -u nobody -p -s /var/lib/fog/tftp/" # /etc/init.d/tftpd-hpa restart