Web Application RPM
Generic Instructions for building a Web Application RPM
RPMS make installation more reliable and removal much easier.
This guide aims to create a common structure for building rpms
Build environment
Local Server
Create a build environment on your local server, refer to the SME Server Developer's Guide: How to create a SME Server package - step by step
SME Build Server
When you are comfortable building rpms, you are encouraged to put your source files on the SME Build Server, Package Modification, this allows others to more easily update and improve your rpms.
The Application RPM
Application source
Download the application source, eg foo.tar.gz and place in the SOURCES directory
SPEC file
Edit the following sample .spec file and place in the SPECS directory
%define name foo %define version 3.6.431 %define release 1 Summary: foo is a helpdesk system Name: %{name} Version: %{version} Release: %{release}%{?dist} Distribution: SME Server License: GNU GPL version 2 URL: http://www.fooweb.com Group: SMEserver/addon #wget http://www.fooweb.com/downloads/foo-3.6.431.tar.gz Source: foo-3.6.431.tar.gz Packager: Stephen Foo <support@foo.net> BuildArchitectures: noarch BuildRoot: /var/tmp/%{name}-%{version} BuildRequires: e-smith-devtools Requires: e-smith-release >= 7.0 AutoReqProv: no %description http://foo.org/ foo is a helpdesk system %changelog * Thu Sep 13 2007 Stephen Foo <support@foo.net> 3.6.431-1 - initial release - builds from unchanged .tar.gz %prep %setup -c -n %{name} %build #drop in an unchanged .tgz, if required rename directory here, eg remove version number. mkdir -p root/opt/ mv %{name} root/opt/foo %install rm -rf $RPM_BUILD_ROOT (cd root ; find . -depth -print | cpio -dump $RPM_BUILD_ROOT) rm -f %{name}-%{version}-filelist /sbin/e-smith/genfilelist $RPM_BUILD_ROOT \ --dir '/opt/foo/tempdir/' 'attr(775,www,www)' \ --file '/opt/foo/logo.gif' 'attr(660,www,www)' \ > %{name}-%{version}-filelist %clean cd .. rm -rf %{name} %files -f %{name}-%{version}-filelist %defattr(-,root,root)
Build the RPM
rpmbuild -ba /home/e-smith/files/users/jim/home/rpms/SPECS/foo.spec
Notes
Permissions, may need tweaking but usually not many need changing, you don't want the webserver changing the distribution files.
Check the .spec files of other contribs, see the CVS (SME Contribs)
SME Server Intergration RPM
Create database
- Create password
root/etc/e-smith/db/configuration/migrate/80foo
{ use MIME::Base64 qw(encode_base64); my $rec = $DB->get('foo') || $DB->new_record('foo', {type => 'service'}); my $pw = $rec->prop('DbPassword'); return "" if $pw; $rec->set_prop('DbPassword', MIME::Base64::encode(int( (1000000000000000) * rand() ))); }
- Create structure
root/etc/e-smith/templates/etc/e-smith/sql/init/80foo
{ my $db = $foo{DbName} || 'foo'; my $user = $foo{DbUser} || 'foo'; my $pass = $foo{DbPassword} || 'foo'; $OUT .= <<END #! /bin/sh if [ -d /var/lib/mysql/$db ]; then exit fi /usr/bin/mysql <<EOF CREATE DATABASE $db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; use $db; #Insert application specific command to create database structure source /opt/foo/sql/mysql_foo.sql; use mysql; GRANT ALL PRIVILEGES ON $db.* TO $user\@localhost IDENTIFIED BY '$pass'; flush privileges; EOF END }
See the %build section of the spec file where you create the DB name & user.
The %post section of the spec file run the commands to initialise db values and create the db structure
db defaults
Reserve the foo name in accounts and create default settings in configuration
Create files in these locations, with default values
root/etc/e-smith/db/accounts/defaults/foo root/etc/e-smith/db/accounts/defaults/foo/type > reserved root/etc/e-smith/db/configuration/defaults/foo root/etc/e-smith/db/configuration/defaults/foo/type > service root/etc/e-smith/db/configuration/defaults/foo/Name > Helpdesk root/etc/e-smith/db/configuration/defaults/foo/PublicAccess > global-pw-remote root/etc/e-smith/db/configuration/defaults/foo/status > enabled root/etc/e-smith/db/configuration/defaults/foo/DbName > foo root/etc/e-smith/db/configuration/defaults/foo/DbUser > foo root/etc/e-smith/templates.metadata/etc/e-smith/sql/init root/etc/e-smith/templates.metadata/etc/e-smith/sql/init/80foo > PERMS=0750
Webserver templates
Http Template 92Foo
The alias fragment tailored to suit the application root/etc/e-smith/templates/etc/httpd/conf/httpd.conf/92foo
{ my $status = $foo{'status'} || "disabled"; return " # foo is disabled in this VirtualHost" unless $status eq 'enabled'; $OUT = ""; my $allow = 'all'; my $pass = '0'; my $satisfy = 'all'; my $name = $foo{'Name'} || 'Application Description'; for ('exit-if-none') { if ($foo{'PublicAccess'}) { if ($foo{'PublicAccess'} eq 'none') { next; } elsif ($foo{'PublicAccess'} eq 'local') { $allow = $localAccess; $pass = 0; $satisfy = 'all'; } elsif ($foo{'PublicAccess'} eq 'local-pw') { $allow = $localAccess; $pass = 1; $satisfy = 'all'; } elsif ($foo{'PublicAccess'} eq 'global') { $allow = 'all'; $pass = 0; $satisfy = 'all'; } elsif ($foo{'PublicAccess'} eq 'global-pw') { $allow = 'all'; $pass = 1; $satisfy = 'all'; } elsif ($foo{'PublicAccess'} eq 'global-pw-remote') { $allow = $localAccess; $pass = 1; $satisfy = 'any'; } } $OUT .= "#------------------------------------------------------------\n"; $OUT .= "# foo - $name\n"; $OUT .= "#------------------------------------------------------------\n"; { if (exists $foo{'URL'}) { $OUT .= "Alias /$foo{'URL'} /opt/foo\n"; } } $OUT .= "Alias /foo /opt/foo\n"; $OUT .= "\n"; $OUT .= "<Directory /opt/foo>\n"; $OUT .= " AddType application/x-httpd-php .php\n"; $OUT .= " php_admin_value open_basedir /opt/foo\n"; $OUT .= " Options None\n"; $OUT .= " order deny,allow\n"; $OUT .= " deny from all\n"; $OUT .= " allow from $allow\n"; $OUT .= " php_value mysql.default_host $foo{DbName}\n"; $OUT .= " php_value mysql.default_user $foo{DbUser}\n"; $OUT .= " php_value mysql.default_password $foo{DbPassword}\n"; if ($pass) { $OUT .= " AuthName \"$name\"\n"; $OUT .= " AuthType Basic\n"; $OUT .= " AuthBasicProvider external\n"; $OUT .= " AuthExternal pwauth\n"; $OUT .= " require valid-user\n"; $OUT .= " Satisfy $satisfy\n"; } $OUT .= "</Directory>\n"; } }
Apache Authentication
In the example above, all sme users can authenticate to the web folder /opt/foo, for an application with no matter in security, it is normal but in certain case it could be dangerous.
- All users of SME Server
The original template in /etc/e-smith/templates/etc/httpd/conf/httpd.conf/92foo
{ $OUT .= " AuthName \"$name\"\n"; $OUT .= " AuthType Basic\n"; $OUT .= " AuthBasicProvider external\n"; $OUT .= " AuthExternal pwauth\n"; $OUT .= " require valid-user\n"; $OUT .= " Satisfy $satisfy\n"; }
- one user or several users
Now you need to modify the 92foo template with these new lines nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/92foo
{ $OUT .= " AuthName \"$name\"\n"; $OUT .= " AuthType Basic\n"; $OUT .= " AuthBasicProvider external\n"; $OUT .= " AuthExternal pwauth\n"; $OUT .= " require user admin pierre paul\n"; $OUT .= " Satisfy $satisfy\n"; }
- one group or several groups with some specific users
You have to download a plugin of pwauth to authenticate unix group in SME Server 8 : http://code.google.com/p/pwauth/
For SME Server 9 a nfr is raised see bugzilla:3690
wget http://pwauth.googlecode.com/files/pwauth-2.3.10.tar.gz tar xvzf pwauth-2.3.10.tar.gz cp pwauth-2.3.10/unixgroup /usr/lib/httpd/modules/ chown root:www /usr/lib/httpd/modules/unixgroup chmod 750 /usr/lib/httpd/modules/unixgroup
We need to create a new fragment
nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/35-group-auth
{ $OUT .= " AddExternalGroup unixgroup /usr/lib/httpd/modules/unixgroup\n"; $OUT .= " SetExternalGroupMethod unixgroup environment\n"; }
Now you need to modify the 92foo template with these new lines nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/92foo
{ $OUT .= " AuthName \"$name\"\n"; $OUT .= " AuthType Basic\n"; $OUT .= " AuthBasicProvider external\n"; $OUT .= " AuthExternal pwauth\n"; $OUT .= " GroupExternal unixgroup\n"; $OUT .= " AuthzUserAuthoritative off\n"; $OUT .= " require user admin pierre paul\n"; $OUT .= " require group virt\n"; $OUT .= " Satisfy $satisfy\n"; }
- DB command to choose groups and users
Above we have seen how to write name of groups or users directly in the template, but in the real life it is not enough good :)
The purpose is to choose users or groups by command line.
-In first you have to make other DB configuration as described Web_Application_RPM#db_defaults
echo "admin" > root/etc/e-smith/db/configuration/defaults/foo/User echo "" > root/etc/e-smith/db/configuration/defaults/foo/Group
Only the user admin is set by default
-You have to download a plugin of pwauth to authenticate unix group in SME Server 8 : http://code.google.com/p/pwauth/
wget http://pwauth.googlecode.com/files/pwauth-2.3.10.tar.gz tar xvzf pwauth-2.3.10.tar.gz cp pwauth-2.3.10/unixgroup /usr/lib/httpd/modules/ chown root:www /usr/lib/httpd/modules/unixgroup chmod 750 /usr/lib/httpd/modules/unixgroup
We need to create a new fragment
nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/35-group-auth
{ $OUT .= " AddExternalGroup unixgroup /usr/lib/httpd/modules/unixgroup\n"; $OUT .= " SetExternalGroupMethod unixgroup environment\n"; }
Now you need to modify the 92foo template with these new lines
nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/92foo
{ $OUT .= " AuthName \"$name\"\n"; $OUT .= " AuthType Basic\n"; $OUT .= " AuthExternal pwauth\n"; $OUT .= " GroupExternal unixgroup\n"; $OUT .= " AuthzUserAuthoritative off\n"; $OUT .= " require user $foo{'User'}\n"; $OUT .= " require group $foo{'Group'}\n"; $OUT .= " Satisfy $satisfy\n"; }
-change groups and users allowed by CL
config setprop foo User "admin toto" config setprop foo Group "famille virt"
then
signal-event console-save
SME Server 9
The apache authentication is made by a new file named authnz_external_module instead of auth_external_module, therefore you need to slightly modify the code above.
If it is not done you can have this error in log file and you won't be authenticated
configuration error: couldn't check user. No user file?:
See this howTo. You need to verify if your /etc/httpd/conf/httpd.conf contain these lines
AddExternalGroup unixgroup /usr/bin/unixgroup SetExternalGroupMethod unixgroup environment
We are waiting the default use of authenticator unixgroup in sme9 (see bugzilla:8008). For now you need to make the relevant fragment template.
nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/35-group-auth
{ $OUT .= " AddExternalGroup unixgroup /usr/bin/unixgroup\n"; $OUT .= " SetExternalGroupMethod unixgroup environment\n"; }
nano /etc/e-smith/templates/etc/httpd/conf/httpd.conf/92foo
{ $OUT .= " AuthName \"$name\"\n"; $OUT .= " AuthBasicProvider external\n"; $OUT .= " AuthType Basic\n"; $OUT .= " AuthExternal pwauth\n"; $OUT .= " GroupExternal unixgroup\n"; $OUT .= " AuthzUserAuthoritative off\n"; $OUT .= " require user $foo{'User'}\n"; $OUT .= " require group $foo{'Group'}\n"; $OUT .= " Satisfy $satisfy\n"; }
-change groups and users allowed by CL
config setprop foo User "admin toto" config setprop foo Group "famille virt"
then
signal-event console-save
Upload_tmp_dir
Since SME Server V8, you could have sometime an error is thrown by PHP and you will need to specify a temporary directory (e.g. upload_tmp_dir) which is not set in php.ini. see bugzilla:6650 and bugzilla:7652. Many Php applications needs this setting, most of known are wordpress, roudcube, egroupware, etc. Symptoms are that you can't upload contents to the PHP application.
An easy way is to make a Custom Template to resolve this issue.
see Uploadtmpdir
Https_redirection
- a hack to get https to work, a better solution is required, you can see Https_redirection
root/etc/e-smith/templates/etc/httpd/conf/httpd.conf/VirtualHosts/30FooAlias
{ my $status = $foo{'status'} || "disabled"; return " # foo is disabled in this VirtualHost" unless $status eq 'enabled'; if ($port eq "443") { $OUT .= " ProxyPass /foo http://127.0.0.1/foo\n"; } }
- or this solution which does the automatic redirection to https protocol, you have to choose either 30FooAlias or 60FooAlias but not both.
root/etc/e-smith/templates/etc/httpd/conf/httpd.conf/VirtualHosts/60FooAlias
{ my $status = $foo{'status'} || "disabled"; return " # foo is disabled in this VirtualHost" unless $status eq 'enabled'; { if ($port ne "443") { $OUT .= <<'HERE'; ## Redirect Web Address to Secure Address RewriteEngine on RewriteRule ^/foo https://%{HTTP_HOST}/foo ## End Of Redirect HERE } } }
- To enforce the security you can decide to prohibit all connexions which are not https. You need to add "SSLRequireSSL" in the correct position of the 92foo template.
$OUT .= "<Directory /opt/foo>\n"; $OUT .= " SSLRequireSSL\n"; $OUT .= " AddType application/x-httpd-php .php\n";
System file templates
You may need to create a fragment for a system file such as crontab.
http://wiki.contribs.org/SME_Server:Documentation:Developers_Manual
Application templates
Preferably include the original application config file in the templates directory,
then overwrite key values, some of which we keep in SME DB's
This is not always possible, eg your application modifies the config file
in this case leave the config file untemplated and advise the user how to configure manually.
eg . root\etc\template\opt\foo\config.php
template-begin
{ $OUT = <<HERE; <?php /* HERE $OUT .= Text::Template::_load_text("/etc/e-smith/templates-default/template-begin"); $OUT .= <<HERE; */ HERE }
template-end
?>
10config-dist
{ $OUT = "require_once('config.php.dist');"; }
20config-sme
// SME Server Settings { $OUT .= "\$CFG->dbname = ini_get\(\'mysql.default_host\'\)\; \n"; $OUT .= "\$CFG->dbuser = ini_get\(\'mysql.default_user\'\)\; \n"; $OUT .= "\$CFG->dbpass = ini_get\(\'mysql.default_password\'\)\; \n"; $OUT .= "\$CFG->dirroot = \'/opt/foo'\; \n"; }
Spec file
%define name smeserver-foo %define version 1.0 %define release 1 Summary: smserver rpm to setup foo, a foo system Name: %{name} Version: %{version} Release: %{release}%{?dist} Distribution: SME Server License: GNU GPL version 2 URL: http://www.foo.net/ Group: SMEserver/addon Source: %{name}-%{version}.tar.gz #Patch0: smeserver-foo-1.0-null.patch Packager: Stephen Foo<support@foo.net> BuildArchitectures: noarch BuildRequires: e-smith-devtools >= 1.13.1-03 BuildRoot: /var/tmp/%{name}-%{version} Requires: e-smith-release >= 7.0 Requires: foo AutoReqProv: no %description smserver rpm to setup foo, a helpdesk system %changelog * Thu Sep 13 2007 Stephen Foo<support@foo.net> 1.0-1 - initial release %prep %setup #%patch0 -p1 %build %install rm -rf $RPM_BUILD_ROOT (cd root ; find . -depth -print | cpio -dump $RPM_BUILD_ROOT) rm -f %{name}-%{version}-filelist /sbin/e-smith/genfilelist $RPM_BUILD_ROOT > %{name}-%{version}-filelist echo "%doc COPYING" >> %{name}-%{version}-filelist %clean cd .. rm -rf %{name}-%{version} %pre %preun %post %postun #uninstall if [ $1 = 0 ] ; then /sbin/e-smith/expand-template /etc/httpd/conf/httpd.conf /usr/bin/sv h /service/httpd-e-smith /sbin/e-smith/expand-template /etc/crontab fi %files -f %{name}-%{version}-filelist %defattr(-,root,root)
Further Information
Developer guide
http://wiki.contribs.org/SME_Server:Documentation:Developers_Manual
New DB settings
- To disable foo. (default is enabled)
config setprop foo status disabled
- To limit access to foo.
config setprop foo PublicAccess OPTION
OPTION is either of the following.
none => No access local => Local network (no password required) local-pw => Local network (password required) global => Entire Internet(no password required) global-pw => Entire Internet(password required) global-pw-remote => Entire Internet(password required outside local network)
- change groups and users allowed by CL
config setprop foo User "admin toto" config setprop foo Group "famille virt"
then
signal-event console-save
- To add a different URL eg. yourserver.net/foo
note, this adds another url, it doesn't remove the default
config setprop foo URL newfoo
- To run foo from the root of a domain, This option is buggy to remove
config delprop foo domain
To enable your changes run these commands
expand-template /etc/httpd/conf/httpd.conf sv h /service/httpd-e-smith
Related applications
- eaccelerator
php applications may be faster with eaccelerator
RPM originally prepared for SME by MasterSleepy and is now in the SMEContribs repo.