Skip to content

Instantly share code, notes, and snippets.

@Kindrat
Last active January 1, 2025 04:06
Show Gist options
  • Save Kindrat/45fee455c39b1958692a to your computer and use it in GitHub Desktop.
Save Kindrat/45fee455c39b1958692a to your computer and use it in GitHub Desktop.

Revisions

  1. Kindrat revised this gist May 4, 2014. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions guide.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,12 @@
    Tested requirements:
    - Ubuntu 14.04 LTS amd64
    - PostgreSQL 9.3.4
    - lf-core 3.0.1
    - webmcp 1.2.5
    - rocketwiki-lqfb 0.4
    - lf-frontend 2.2.5
    - lighttpd 1.4.33-1+nmu2ubuntu2

    Add postgresql repository (check distro version). Create `/etc/apt/sources.list.d/pgdg.list`. Add there `deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main`

    wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
  2. Kindrat renamed this gist May 4, 2014. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. Kindrat created this gist May 4, 2014.
    398 changes: 398 additions & 0 deletions liquid-feedback installation guide.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,398 @@
    Add postgresql repository (check distro version). Create `/etc/apt/sources.list.d/pgdg.list`. Add there `deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main`

    wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

    Install debian security updates:

    apt-get update
    apt-get upgrade

    Install the neccessary debian packages:

    apt-get install lua5.1 postgresql postgresql-server-${version}-dev build-essential libpq-dev liblua5.1-0-dev lighttpd ghc libghc-parsec3-dev imagemagick exim4 nano

    > +500MB
    Create a database role for www-data:

    createuser www-data
    passwd postgres
    su - postgres
    psql
    postgres-# ALTER ROLE postgres WITH PASSWORD 'postgres';
    postgres-# CREATE USER liquid WITH PASSWORD 'feedback';
    postgres-# CREATE DATABASE lf;
    postgres=# GRANT ALL PRIVILEGES ON DATABASE lf to liquid;
    postgres=# \q
    exit

    Make `www-data` user possible to login with. Edit `/etc/passwd`. Find *www-data* entry and change shell from `/usr/sbin/nologin` to `/bin/bash` (or what you prefer)

    Configure db connection. Edit `/etc/postgres/${version}/main/pg_hba.conf`, change `peer` to `md5`

    local all postgres md5
    # TYPE DATABASE USER ADDRESS METHOD
    # "local" is for Unix domain socket connections only
    local all all md5

    Reload postgres configuration:


    service postgresql reload
    Create a directory for unpacking source tarballs:

    cd /root
    mkdir install
    Install and configure LiquidFeedback Core:

    cd /root/install
    wget http://www.public-software-group.org/pub/projects/liquid_feedback/backend/v3.0.1/liquid_feedback_core-v3.0.1.tar.gz
    tar -xvzf liquid_feedback_core-v3.0.1.tar.gz
    cd liquid_feedback_core-v3.0.1
    make
    mkdir /opt/liquid_feedback_core
    cp core.sql lf_update /opt/liquid_feedback_core/
    chmod u+rwXs,g+rwXs -R /opt/liquid_feedback_core/
    chown www-data:www-data -R /opt/liquid_feedback_core/
    su - www-data
    cd /opt/liquid_feedback_core
    psql -U liquid -v ON_ERROR_STOP=1 -f core.sql lf
    psql -U liquid -d lf

    lf=> SELECT * FROM liquid_feedback_version;
    string | major | minor | revision
    --------+-------+-------+----------
    3.0.1 | 3 | 0 | 1
    (1 row)

    lf=> SELECT * FROM system_setting;
    member_ttl
    ------------
    (0 rows)

    lf=> INSERT INTO system_setting (member_ttl) VALUES ('1 year');
    INSERT 0 1

    lf=> SELECT * FROM contingent;
    polling | time_frame | text_entry_limit | initiative_limit
    ---------+------------+------------------+------------------
    (0 rows)

    lf=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (false, '1 hour', 20, 6);
    INSERT 0 1

    lf=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (false, '1 day', 80, 12);
    INSERT 0 1

    lf=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (true, '1 hour', 200, 60);
    INSERT 0 1

    lf=> INSERT INTO contingent (polling, time_frame, text_entry_limit, initiative_limit) VALUES (true, '1 day', 800, 120);
    INSERT 0 1

    lf=> 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)

    lf=> 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

    lf=> 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)

    lf=> SELECT * FROM unit;
    id | parent_id | active | name | description | member_count | text_search_data
    ----+-----------+--------+------+-------------+--------------+------------------
    (0 rows)

    lf=> INSERT INTO unit (name) VALUES ('Our organization');
    INSERT 0 1

    lf=> SELECT * FROM unit;
    id | parent_id | active | name | description | member_count | text_search_data
    ----+-----------+--------+------------------+-------------+--------------+--------------------------
    1 | | t | Our organization | | | 'organization':2 'our':1
    (1 row)

    lf=> SELECT * FROM area;
    id | unit_id | active | name | description | direct_member_count | member_weight | text_search_data
    ----+---------+--------+------+-------------+---------------------+---------------+------------------
    (0 rows)

    lf=> INSERT INTO area (unit_id, name) VALUES (1, 'Default area');
    INSERT 0 1

    lf=> 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)

    lf=> SELECT * FROM allowed_policy;
    area_id | policy_id | default_policy
    ---------+-----------+----------------
    (0 rows)

    lf=> INSERT INTO allowed_policy (area_id, policy_id, default_policy) VALUES (1, 1, TRUE);
    INSERT 0 1

    liquid_feedback=> \q

    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
    nano Makefile.options
    # append -I /usr/include/lua5.1 at end of CFLAGS line
    # change -I /usr/include/postgresql -I /usr/include/postgresql/server to
    # -I /usr/include/postgresql/${version} -I /usr/include/postgresql/${version}/server
    # append -I /usr/include/postgresql at end of CFLAGS_PGSQL
    make
    mkdir /opt/webmcp
    cp -RL framework/* /opt/webmcp/
    chown www-data:www-data -R /opt/webmcp/
    chmod u+rwXs,g+rwXs -R /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/
    chown www-data:www-data -R /opt/rocketwiki-lqfb/
    chmod u+rwXs,g+rwXs -R /opt/rocketwiki-lqfb/
    Install LiquidFeedback-Frontend:

    cd /root/install
    wget http://www.public-software-group.org/pub/projects/liquid_feedback/frontend/v2.2.5/liquid_feedback_frontend-v2.2.5.tar.gz
    tar -xvzf liquid_feedback_frontend-v2.2.5.tar.gz
    mv liquid_feedback_frontend-v2.2.5 /opt/liquid_feedback_frontend
    chown www-data:www-data -R /opt/liquid_feedback_frontend
    chmod u+rwXs,g+rwXs -R /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
    nano getpic.c
    check#define GETPIC_CONNINFO "dbname=lf"
    make

    Configure mail system:


    dpkg-reconfigure exim4-config
    Create webserver configuration for LiquidFeedback:

    cd /etc/lighttpd
    nano conf-available/60-liquidfeedback.conf
    server.modules += ("mod_cgi", "mod_rewrite", "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
    nano 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
    Set database options

    config.database = { engine='postgresql', dbname='lf', user='liquid', password='feedback' }

    Edit vHost name:


    config.absolute_base_url = "http://liquid-feedback.local/"

    Execute lf_update once:

    su - www-data
    cd /opt/liquid_feedback_core
    ./lf_update dbname=lf user=liquid password=feedback && echo OK
    exit

    The commands `lf_update dbname=lf user=liquid password=feedback` and `lf_update_suggestion_order dbname=lf user=liquid password=feedback` have to be executed regulary. Create the following shell script to call this command in an endless loop:


    nano /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=lf user=liquid password=feedback 2>&1 | logger -t "lf_updated"'
    su - www-data -c 'nice /opt/liquid_feedback_core/lf_update_suggestion_order dbname=lf user=liquid password=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...

    nano /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 lf_updated defaults
    Start sending of event notifications:

    su - www-data -c 'cd /opt/liquid_feedback_frontend/ && nohup echo "Event:send_notifications_loop()" | ../webmcp/bin/webmcp_shell myconfig &>/dev/null &'
    Restart the webserver:


    /etc/init.d/lighttpd restart
    Create an administrator account:

    su - www-data
    cd /opt/liquid_feedback_core
    psql -U liquid -d lf

    lf=> INSERT INTO member (login, name, admin, invite_code) VALUES ('admin', 'Administrator', TRUE, _INSERT_ADMIN_INVITE_CODE_IN_SINGLE_QUOTES_HERE_);
    INSERT 0 1

    lf=> \q
    exit