====== Lightweight groupware solution using nginx+php-fpm+mysql+baïkal+roundcube+agendav ======
The goal of this document is to set up a web-based solution providing mail, calendars and contacts management, along with mobile devices & desktop synchronization using dav* protocols.
This obviously needs an already running full mail stack (I use qmail/postfix/dovecot), which will not be covered there. This document also assume that nginx, fpm and mysql are also already up and running.
===== nginx =====
server {
# put listen directives & tls stuff here #
server_name sub.domain.tld;
access_log /var/log/nginx/groupware-access.log;
error_log /var/log/nginx/groupware-error.log;
location / {
index index.php;
root /path/to/roundcube;
dav_ext_methods PROPFIND OPTIONS;
# support for csrf token
rewrite "^/[a-zA-Z0-9]{16}/(.*)" /$1 break;
# good ol' favicon (adjust path if you use Larry skin)
rewrite ^/favicon.ico /skins/classic/images/favicon.ico last;
# caldav/carddav stuff
rewrite ^/addressbooks/(.*) /dav/card.php/addressbooks/$1 redirect;
rewrite ^/calendars/(.*) /dav/cal.php/calendars/$1 redirect;
rewrite ^/.well-known/carddav /dav/dav.php redirect;
rewrite ^/.well-known/caldav /dav/dav.php redirect;
# maximum upload size for mail attachments
client_max_body_size 30M;
location ~ .php {
include fastcgi_params;
fastcgi_param HTTPS on;
fastcgi_split_path_info (.+.php)(/.*)$;
fastcgi_pass unix:/path/to/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
location /dav {
root /path/to/baikal;
index index.php;
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS;
charset utf-8;
location ~ /(\.ht|Core|Specific) {
deny all;
return 404;
}
location ~ ^(.+\.php)(.*)$ {
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_pass unix:/path/to/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
}
===== Baïkal =====
curl -L -O https://github.com/fruux/Baikal/releases/download/0.4.6/baikal-0.4.6.zip
unzip baikal-0.4.6.zip && rm -f baikal-0.4.6.zip
ln -s baikal-0.4.6 baikal
===== Roundcube =====
* First, you need to create a database. Here we created a mysql database named roundcubemail, hosted on “dbhost” and owned by user roundcubemail.
* Install roundecube:
curl -L -O https://github.com/roundcube/roundcubemail/releases/download/1.3.3/roundcubemail-1.3.3-complete.tar.gz
tar xvf roundcubemail-1.3.3-complete.tar.gz && rm -f roundcubemail-1.3.3-complete.tar.gz
ln -s roundcubemail-1.3.3 roundcube
cd roundcube
mysql -h dbhost -u roundcubemail -p roundcubemail < SQL/mysql.initial.sql
===== AgenDAV plugin =====
* First, you need to create a database. Here we created a mysql database named agendav, hosted on "dbhost" and owned by user agendav.
* Install AgenDAV plugin:
cd roundcube/plugins
git clone https://github.com/stephanblanke/roundcube-agendav.git agendav
curl -L -O https://github.com/adobo/agendav/archive/1.2.6.2.tar.gz
tar xvf 1.2.6.2.tar.gz && rm 1.2.6.2.tar.gz
cp agendav-1.2.6.2.css agendav-1.2.6.2/web/public/css/agendav-1.2.6.2.css
cd agendav-1.2.6.2
mysql -h dbhost -u agendav -p agendav < sql/mysql.schema.sql
* Adjust var in plugins/agendav/agendav-1.2.6.2/web/config/config.php
* Adjust caldav parameters in plugins/agendav/agendav-1.2.6.2/web/config/caldav.php:
$config['caldav_http_auth_method'] = CURLAUTH_BASIC;
$config['caldav_principal_url'] = 'https://sub.domain.tld/dav/cal.php/%u/default';
$config['caldav_calendar_url'] = 'https://sub.domain.tld/.well-known/caldav';
$config['public_caldav_url'] = 'https://sub.domain.tld/dav/cal.php/%s/';
* Adjust vars in plugins/agendav/agendav-1.2.6.2/web/config/database.php:
$db['default']['hostname'] = 'dbhost';
$db['default']['username'] = 'agendav';
$db['default']['password'] = 'changeme';
$db['default']['database'] = 'agendav';
$db['default']['dbdriver'] = 'mysql';
* For french translation, create plugins/agendav/localization/fr_FR.inc:
.inc |
| |
| Localization file of the Roundcube Webmail Help plugin |
| Copyright (C) 2012-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
+-----------------------------------------------------------------------+
For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-help/
*/
$labels = array();
$labels['agendav'] = 'Calendrier';
$labels['prefs'] = 'Préférences';
?>
* If using classic skin, replace the strange "interrogation mark" button by a prettier one:
mv plugins/agendav/skins/classic/agendav.gif plugins/agendav/skins/classic/agendav.old.gif
curl -o plugins/agendav/skins/classic/agendav.gif https://git.kolab.org/file/data/kamnlpzz2fmtbgygywso/PHID-FILE-2ozl7pm2enflqcndiowh/calendar.gif
==== PHP7 ====
If using php7, you need to patch agendav 1.2.6.2
* plugins/agendav/agendav-1.2.6.2/web/system/database/drivers/mysql/mysql_driver.php
--- agendav-1.2.6.2.old/web/system/database/drivers/mysql/mysql_driver.php 2012-10-15 09:54:01.000000000 +0200
+++ agendav-1.2.6.2/web/system/database/drivers/mysql/mysql_driver.php 2017-07-09 16:18:32.673770000 +0200
@@ -88,7 +88,7 @@
$this->hostname .= ':'.$this->port;
}
- return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
}
// --------------------------------------------------------------------
@@ -120,7 +120,8 @@
*/
function db_select()
{
- return @mysql_select_db($this->database, $this->conn_id);
+ //return @mysqli_select_db($this->database, $this->conn_id);
+ return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
}
// --------------------------------------------------------------------
@@ -138,16 +139,16 @@
if ( ! isset($this->use_set_names))
{
// mysql_set_charset() requires PHP >= 5.2.3 and MySQL >= 5.0.7, use SET NAMES as fallback
- $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysql_get_server_info(), '5.0.7', '>=')) ? FALSE : TRUE;
+ $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysqli_get_server_info($this->conn_id), '5.0.7', '>=')) ? FALSE : TRUE;
}
if ($this->use_set_names === TRUE)
{
- return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id);
+ return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
}
else
{
- return @mysql_set_charset($charset, $this->conn_id);
+ return @mysqli_set_charset($charset, $this->conn_id);
}
}
@@ -176,7 +177,7 @@
function _execute($sql)
{
$sql = $this->_prep_query($sql);
- return @mysql_query($sql, $this->conn_id);
+ return @mysqli_query($this->conn_id, $sql);
}
// --------------------------------------------------------------------
@@ -342,7 +343,7 @@
*/
function affected_rows()
{
- return @mysql_affected_rows($this->conn_id);
+ return @mysqli_affected_rows($this->conn_id);
}
// --------------------------------------------------------------------
@@ -355,7 +356,7 @@
*/
function insert_id()
{
- return @mysql_insert_id($this->conn_id);
+ return @mysqli_insert_id($this->conn_id);
}
// --------------------------------------------------------------------
@@ -454,7 +455,7 @@
*/
function _error_message()
{
- return mysql_error($this->conn_id);
+ return mysqli_error($this->conn_id);
}
// --------------------------------------------------------------------
@@ -467,7 +468,7 @@
*/
function _error_number()
{
- return mysql_errno($this->conn_id);
+ return mysqli_errno($this->conn_id);
}
+ return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
}
// --------------------------------------------------------------------
@@ -138,16 +139,16 @@
if ( ! isset($this->use_set_names))
{
// mysql_set_charset() requires PHP >= 5.2.3 and MySQL >= 5.0.7, use SET NAMES as fallback
- $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysql_get_server_info(), '5.0.7', '>=')) ? FALSE : TRUE;
+ $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysqli_get_server_info($this->conn_id), '5.0.7', '>=')) ? FALSE : TRUE;
}
if ($this->use_set_names === TRUE)
{
- return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id);
+ return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
}
else
{
- return @mysql_set_charset($charset, $this->conn_id);
+ return @mysqli_set_charset($charset, $this->conn_id);
}
}
@@ -176,7 +177,7 @@
function _execute($sql)
{
$sql = $this->_prep_query($sql);
- return @mysql_query($sql, $this->conn_id);
+ return @mysqli_query($this->conn_id, $sql);
}
// --------------------------------------------------------------------
@@ -342,7 +343,7 @@
*/
function affected_rows()
{
- return @mysql_affected_rows($this->conn_id);
+ return @mysqli_affected_rows($this->conn_id);
}
// --------------------------------------------------------------------
@@ -355,7 +356,7 @@
*/
function insert_id()
{
- return @mysql_insert_id($this->conn_id);
+ return @mysqli_insert_id($this->conn_id);
}
// --------------------------------------------------------------------
@@ -454,7 +455,7 @@
*/
function _error_message()
{
- return mysql_error($this->conn_id);
+ return mysqli_error($this->conn_id);
}
// --------------------------------------------------------------------
@@ -467,7 +468,7 @@
*/
function _error_number()
{
- return mysql_errno($this->conn_id);
+ return mysqli_errno($this->conn_id);
}
// --------------------------------------------------------------------
@@ -769,11 +770,11 @@
*/
function _close($conn_id)
{
- @mysql_close($conn_id);
+ @mysqli_close($conn_id);
}
}
/* End of file mysql_driver.php */
-/* Location: ./system/database/drivers/mysql/mysql_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/mysql/mysql_driver.php */
* plugins/agendav/agendav-1.2.6.2/web/system/database/drivers/mysql/mysql_result.php
--- agendav-1.2.6.2.old/web/system/database/drivers/mysql/mysql_result.php 2012-10-15 09:54:01.000000000 +0200
+++ agendav-1.2.6.2/web/system/database/drivers/mysql/mysql_result.php 2017-07-09 18:06:06.572461000 +0200
@@ -34,7 +34,7 @@
*/
function num_rows()
{
- return @mysql_num_rows($this->result_id);
+ return @mysqli_num_rows($this->result_id);
}
// --------------------------------------------------------------------
@@ -134,7 +134,7 @@
*/
function _data_seek($n = 0)
{
- return mysql_data_seek($this->result_id, $n);
+ return mysqli_data_seek($this->result_id, $n);
}
// --------------------------------------------------------------------
@@ -149,7 +149,7 @@
*/
function _fetch_assoc()
{
- return mysql_fetch_assoc($this->result_id);
+ return mysqli_fetch_assoc($this->result_id);
}
// --------------------------------------------------------------------
@@ -164,11 +164,11 @@
*/
function _fetch_object()
{
- return mysql_fetch_object($this->result_id);
+ return mysqli_fetch_object($this->result_id);
}
}
/* End of file mysql_result.php */
-/* Location: ./system/database/drivers/mysql/mysql_result.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/mysql/mysql_result.php */
===== Carddav plugin =====
cd roundcube
curl -s http://getcomposer.org/installer | php
php composer.phar require roundcube/carddav
===== Mobile plugin =====
At the time of writing (2017-07-09), this plugin is [[https://github.com/messagerie-melanie2/Roundcube-Plugin-Mobile/issues/25|incompatible with Roundcube 1.3.0]].
cd roundcube
git clone https://github.com/messagerie-melanie2/Roundcube-Skin-Melanie2-Larry-Mobile.git skins/melanie2_larry_mobile
php composer.phar require melanie2/mobile:dev-master