= How to install LiquidFeedback on a Debian squeeze system with lighttpd Install debian security updates: {{{ apt-get update apt-get upgrade }}} Install the neccessary debian packages: {{{ apt-get install lua5.1 postgresql build-essential libpq-dev liblua5.1-0-dev lighttpd ghc libghc6-parsec3-dev imagemagick exim4 }}} Create a database role for www-data: {{{ su - postgres createuser }}} {{{ Enter name of role to add: www-data Shall the new role be a superuser? (y/n) n Shall the new role be allowed to create databases? (y/n) y Shall the new role be allowed to create more new roles? (y/n) n }}} {{{ exit }}} Create a directory for unpacking source tarballs: {{{ cd /root mkdir install }}} Install and configure LiquidFeedback Core v2.2.1: {{{ cd /root/install wget http://www.public-software-group.org/pub/projects/liquid_feedback/backend/v2.2.1/liquid_feedback_core-v2.2.1.tar.gz tar -xvzf liquid_feedback_core-v2.2.1.tar.gz cd liquid_feedback_core-v2.2.1 make mkdir /opt/liquid_feedback_core cp core.sql lf_update /opt/liquid_feedback_core/ su - www-data cd /opt/liquid_feedback_core createdb liquid_feedback createlang plpgsql liquid_feedback psql -v ON_ERROR_STOP=1 -f core.sql liquid_feedback psql liquid_feedback }}} {{{ psql (8.4.13) Type "help" for help. liquid_feedback=> SELECT * FROM liquid_feedback_version; string | major | minor | revision --------+-------+-------+---------- 2.2.1 | 2 | 2 | 1 (1 row) liquid_feedback=> SELECT * FROM system_setting; member_ttl ------------ (0 rows) liquid_feedback=> INSERT INTO system_setting (member_ttl) VALUES ('1 year'); INSERT 0 1 liquid_feedback=> SELECT * FROM contingent; polling | time_frame | text_entry_limit | initiative_limit ---------+------------+------------------+------------------ (0 rows) liquid_feedback=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (false, '1 hour', 20, 6); INSERT 0 1 liquid_feedback=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (false, '1 day', 80, 12); INSERT 0 1 liquid_feedback=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (true, '1 hour', 200, 60); INSERT 0 1 liquid_feedback=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (true, '1 day', 800, 120); INSERT 0 1 liquid_feedback=> SELECT * FROM policy; id | index | active | name | description | polling | admission_time | discussion_time | verification_time | voting_time | issue_quorum_num | issue_quorum_den | initiative_quorum_num | initiative_quorum_den | direct_majority_num | direct_majority_den | direct_majority_strict | direct_majority_positive | direct_majority_non_negative | indirect_majority_num | indirect_majority_den | indirect_majority_strict | indirect_majority_positive | indirect_majority_non_negative | no_reverse_beat_path | no_multistage_majority ----+-------+--------+------+-------------+---------+----------------+-----------------+-------------------+-------------+------------------+------------------+-----------------------+-----------------------+---------------------+---------------------+------------------------+--------------------------+------------------------------+-----------------------+-----------------------+--------------------------+----------------------------+--------------------------------+----------------------+------------------------ (0 rows) liquid_feedback=> INSERT INTO policy (index, name, admission_time, discussion_time, verification_time, voting_time, issue_quorum_num, issue_quorum_den, initiative_quorum_num, initiative_quorum_den) VALUES (1, 'Default policy', '8 days', '15 days', '8 days', '15 days', 10, 100, 10, 100); INSERT 0 1 liquid_feedback=> SELECT * FROM policy; id | index | active | name | description | polling | admission_time | discussion_time | verification_time | voting_time | issue_quorum_num | issue_quorum_den | initiative_quorum_num | initiative_quorum_den | direct_majority_num | direct_majority_den | direct_majority_strict | direct_majority_positive | direct_majority_non_negative | indirect_majority_num | indirect_majority_den | indirect_majority_strict | indirect_majority_positive | indirect_majority_non_negative | no_reverse_beat_path | no_multistage_majority ----+-------+--------+----------------+-------------+---------+----------------+-----------------+-------------------+-------------+------------------+------------------+-----------------------+-----------------------+---------------------+---------------------+------------------------+--------------------------+------------------------------+-----------------------+-----------------------+--------------------------+----------------------------+--------------------------------+----------------------+------------------------ 1 | 1 | t | Default policy | | f | 8 days | 15 days | 8 days | 15 days | 10 | 100 | 10 | 100 | 1 | 2 | t | 0 | 0 | 1 | 2 | t | 0 | 0 | t | f (1 row) liquid_feedback=> SELECT * FROM unit; id | parent_id | active | name | description | member_count | text_search_data ----+-----------+--------+------+-------------+--------------+------------------ (0 rows) liquid_feedback=> INSERT INTO unit (name) VALUES ('Our organization'); INSERT 0 1 liquid_feedback=> SELECT * FROM unit; id | parent_id | active | name | description | member_count | text_search_data ----+-----------+--------+------------------+-------------+--------------+-------------------------- 1 | | t | Our organization | | | 'organization':2 'our':1 (1 row) liquid_feedback=> SELECT * FROM area; id | unit_id | active | name | description | direct_member_count | member_weight | text_search_data ----+---------+--------+------+-------------+---------------------+---------------+------------------ (0 rows) liquid_feedback=> INSERT INTO area (unit_id, name) VALUES (1, 'Default area'); INSERT 0 1 liquid_feedback=> SELECT * FROM area; id | unit_id | active | name | description | direct_member_count | member_weight | text_search_data ----+---------+--------+--------------+-------------+---------------------+---------------+---------------------- 1 | 1 | t | Default area | | | | 'area':2 'default':1 (1 row) liquid_feedback=> SELECT * FROM allowed_policy; area_id | policy_id | default_policy ---------+-----------+---------------- (0 rows) liquid_feedback=> INSERT INTO allowed_policy (area_id, policy_id, default_policy) VALUES (1, 1, TRUE); INSERT 0 1 liquid_feedback=> \q could not save history to file "/var/www/.psql_history": Permission denied }}} {{{ exit }}} Install WebMCP: {{{ cd /root/install wget http://www.public-software-group.org/pub/projects/webmcp/v1.2.5/webmcp-v1.2.5.tar.gz tar -xvzf webmcp-v1.2.5.tar.gz cd webmcp-v1.2.5 vi Makefile.options # append -I /usr/include/lua5.1 at end of CFLAGS line make mkdir /opt/webmcp cp -RL framework/* /opt/webmcp/ }}} Install RocketWiki LqFb-Edition: {{{ cd /root/install wget http://www.public-software-group.org/pub/projects/rocketwiki/liquid_feedback_edition/v0.4/rocketwiki-lqfb-v0.4.tar.gz tar -xvzf rocketwiki-lqfb-v0.4.tar.gz cd rocketwiki-lqfb-v0.4 make mkdir /opt/rocketwiki-lqfb cp rocketwiki-lqfb rocketwiki-lqfb-compat /opt/rocketwiki-lqfb/ }}} Install LiquidFeedback-Frontend v2.2.1: {{{ cd /root/install wget http://www.public-software-group.org/pub/projects/liquid_feedback/frontend/v2.2.1/liquid_feedback_frontend-v2.2.1.tar.gz tar -xvzf liquid_feedback_frontend-v2.2.1.tar.gz mv liquid_feedback_frontend-v2.2.1 /opt/liquid_feedback_frontend }}} Create HTML code for help texts: {{{ cd /opt/liquid_feedback_frontend/locale PATH=/opt/rocketwiki-lqfb:$PATH make }}} Make tmp directory of LiquidFeedback-Frontend writable for webserver: {{{ chown www-data /opt/liquid_feedback_frontend/tmp }}} Compile binary for fast delivery of member images: {{{ cd /opt/liquid_feedback_frontend/fastpath vi getpic.c }}} {{{ check #define GETPIC_CONNINFO "dbname=liquid_feedback" and replace #define GETPIC_DEFAULT_AVATAR "/opt/liquid_feedback_testing/app/static/avatar.jpg" with #define GETPIC_DEFAULT_AVATAR "/opt/liquid_feedback_frontend/static/avatar.jpg" }}} {{{ make }}} Configure mail system: {{{ dpkg-reconfigure exim4-config }}} Create webserver configuration for LiquidFeedback: {{{ cd /etc/lighttpd vi conf-available/60-liquidfeedback.conf }}} {{{ server.modules += ("mod_cgi", "mod_rewrite", "mod_redirect", "mod_setenv") # Enable CGI-Execution of *.lua files through lua binary cgi.assign += ( ".lua" => "/usr/bin/lua5.1" ) alias.url += ( "/lf/fastpath/" => "/opt/liquid_feedback_frontend/fastpath/", "/lf/static" => "/opt/liquid_feedback_frontend/static", "/lf" => "/opt/webmcp/cgi-bin" ) # Configure environment for demo application $HTTP["url"] =~ "^/lf" { setenv.add-environment += ( "LANG" => "en_US.UTF-8", "WEBMCP_APP_BASEPATH" => "/opt/liquid_feedback_frontend/", "WEBMCP_CONFIG_NAME" => "myconfig") } # URL beautification url.rewrite-once += ( # do not rewrite static URLs "^/lf/fastpath/(.*)$" => "/lf/fastpath/$1", "^/lf/static/(.*)$" => "/lf/static/$1", # dynamic URLs "^/lf/([^\?]*)(\?(.*))?$" => "/lf/webmcp-wrapper.lua?_webmcp_path=$1&$3", ) $HTTP["url"] =~ "^/lf/fastpath/" { cgi.assign = ( "" => "" ) setenv.add-response-header = ( "Cache-Control" => "private; max-age=86400" ) } }}} {{{ cd /etc/lighttpd/conf-enabled ln -s ../conf-available/60-liquidfeedback.conf . }}} Configure LiquidFeedback-Frontend: {{{ cd /opt/liquid_feedback_frontend/config cp example.lua myconfig.lua vi myconfig.lua }}} While configuring the LiquidFeedback-Frontend, use the following option to enable fast image loading: {{{ config.fastpath_url_func = function(member_id, image_type) return request.get_absolute_baseurl() .. "fastpath/getpic?" .. tostring(member_id) .. "+" .. tostring(image_type) end }}} Execute lf_update once: {{{ su - www-data cd /opt/liquid_feedback_core ./lf_update dbname=liquid_feedback && echo OK exit }}} The commands "lf_update dbname=liquid_feedback" and "lf_update_suggestion_order dbname=liquid_feedback" have to be executed regulary. Create the following shell script to call this command in an endless loop: {{{ vi /opt/liquid_feedback_core/lf_updated }}} {{{ #!/bin/sh PIDFILE="/var/run/lf_updated.pid" PID=$$ if [ -f "${PIDFILE}" ] && kill -CONT $( cat "${PIDFILE}" ); then echo "lf_updated is already running." exit 1 fi echo "${PID}" > "${PIDFILE}" while true; do su - www-data -c 'nice /opt/liquid_feedback_core/lf_update dbname=liquid_feedback 2>&1 | logger -t "lf_updated"' su - www-data -c 'nice /opt/liquid_feedback_core/lf_update_suggestion_order dbname=liquid_feedback 2>&1 | logger -t "lf_updated"' sleep 5 done }}} {{{ chmod +x /opt/liquid_feedback_core/lf_updated }}} Create the following init-script for lf_updated... {{{ vi /etc/init.d/lf_updated }}} {{{ #! /bin/sh ### BEGIN INIT INFO # Provides: lf_updated # Required-Start: $syslog # Required-Stop: $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: lf_updated # Description: Calls LiquidFeedback lf_update regulary ### END INIT INFO # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="lf_updated" NAME=lf_updated DAEMON=/opt/liquid_feedback_core/lf_updated DAEMON_ARGS="" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME . /lib/lsb/init-functions do_start() { start-stop-daemon -b --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null || return 1 start-stop-daemon -b --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_ARGS || return 2 } do_stop() { start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 rm -f $PIDFILE return "$RETVAL" } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac : }}} ... and make the init script executable and let it start automatically at boot time {{{ chmod +x /etc/init.d/lf_updated update-rc.d-insserv lf_updated defaults }}} Start sending of event notifications: (TODO: daemonize) {{{ su - www-data cd /opt/liquid_feedback_frontend/ echo "Event:send_notifications_loop()" | ../webmcp/bin/webmcp_shell myconfig }}} Restart the webserver: {{{ /etc/init.d/lighttpd restart }}} Create an administrator account: {{{ su - www-data cd /opt/liquid_feedback_core psql liquid_feedback }}} {{{ psql (8.4.13) Type "help" for help. liquid_feedback=> INSERT INTO member (login, name, admin, invite_code) VALUES ('admin', 'Administrator', TRUE, _INSERT_ADMIN_INVITE_CODE_IN_SINGLE_QUOTES_HERE_); INSERT 0 1 liquid_feedback=> \q could not save history to file "/var/www/.psql_history": No such file or directory }}} {{{ exit }}}