Hi all, I recently installed ISPConfig3 to an openSUSE12.3/Tumbleweed box using this Howto. I had to change/inspect some issues, as follows: - the /etc/my.cnf (and additionally a strange /usr/my.cnf, which seems to come from an invocation of mysql_secure_installation) contained a sql-mode line Code: sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES This SQL-Mode leads to some errors during creation of the ISPConfig database, therefore I had to remove this line before installation. - the install script contains a few errors regarding user/group modification, further in oS12.3 the PureFTPd config has to be changed (Daemonize NO due to systemd), see the diff Code: diff -ur ispconfig3_install/install/dist/lib/opensuse.lib.php ispconfig3_install.new/install/dist/lib/opensuse.lib.php --- ispconfig3_install/install/dist/lib/opensuse.lib.php 2013-08-08 09:09:35.000000000 +0200 +++ ispconfig3_install.new/install/dist/lib/opensuse.lib.php 2013-10-14 23:11:07.652388198 +0200 @@ -528,9 +528,9 @@ } unset($content); - // Add the clamav user to the vscan group - exec('groupmod --add-user clamav vscan'); - + // Add the vscan user to the clamav group + $command = 'usermod -a -G clamav vscan'; + caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); } @@ -1049,18 +1049,18 @@ // and must be fixed as this will allow the apache user to read the ispconfig files. // Later this must run as own apache server or via suexec! if($conf['apache']['installed'] == true){ - $command = 'groupmod --add-user '.$conf['apache']['user'].' ispconfig'; + $command = 'usermod -a -G ispconfig '.$conf['apache']['user']; caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); if(is_group('ispapps')){ - $command = 'groupmod --add-user '.$conf['apache']['user'].' ispapps'; + $command = 'usermod -a -G ispapps '.$conf['apache']['user']; caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); } } if($conf['nginx']['installed'] == true){ - $command = 'groupmod --add-user '.$conf['nginx']['user'].' ispconfig'; + $command = 'usermod -a -G ispconfig '.$conf['nginx']['user']; caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); if(is_group('ispapps')){ - $command = 'groupmod --add-user '.$conf['nginx']['user'].' ispapps'; + $command = 'usermod -a -G ispapps '.$conf['nginx']['user']; caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); } } diff -ur ispconfig3_install/install/lib/installer_base.lib.php ispconfig3_install.new/install/lib/installer_base.lib.php --- ispconfig3_install/install/lib/installer_base.lib.php 2013-08-09 10:46:08.000000000 +0200 +++ ispconfig3_install.new/install/lib/installer_base.lib.php 2013-10-14 23:09:16.404700070 +0200 @@ -1483,7 +1483,7 @@ if(!is_user($apps_vhost_user)) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); - $command = 'adduser '.$conf['apache']['user'].' '.$apps_vhost_group; + $command = 'usermod -a -G '.$apps_vhost_group.' '.$conf['apache']['user']; caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); if(!@is_dir($install_dir)){ diff -ur ispconfig3_install/install/tpl/opensuse_pureftpd_conf.master ispconfig3_install.new/install/tpl/opensuse_pureftpd_conf.master --- ispconfig3_install/install/tpl/opensuse_pureftpd_conf.master 2010-08-23 13:49:01.000000000 +0200 +++ ispconfig3_install.new/install/tpl/opensuse_pureftpd_conf.master 2013-10-14 23:18:38.663123601 +0200 @@ -43,7 +43,7 @@ # Fork in background -Daemonize yes +Daemonize no - to get the phpMyAdmin alias to work with FastCGI I had to add the following Apache Directive Snippet Code: <Directory /srv/www/htdocs/phpMyAdmin> AddHandler fcgid-script .php .php3 .php4 .php5 FCGIWrapper /srv/www/php-fcgi-scripts/web1/.php-fcgi-starter .php Options +ExecCGI AllowOverride All Order allow,deny Allow from all </Directory> and add "/srv/www/htdocs/phpMyAdmin:/etc/phpMyAdmin" to the websites PHP open_basedir. The same is true for Squirrelmail/Roundcube's webmail alias. This can be automated by changing the appropriate line in <ISPConfig3_installer>/install/tpl/server.ini.master before installation or update the server config Web/PHP section. - in order that invocation of http://<ip_of_the_box> would not direct to the first configured virtual host, I had to change some Apache2 config files Code: diff -u /root/down/etc/apache2/default-vhost.conf /etc/apache2/default-vhost.conf --- /root/down/etc/apache2/default-vhost.conf 2013-07-31 14:33:35.000000000 +0200 +++ /etc/apache2/default-vhost.conf 2013-10-21 00:07:56.284714075 +0200 @@ -96,7 +96,7 @@ # http://httpd.apache.org/docs-2.2/mod/core.html#options # for more information. # - Options +Indexes +MultiViews +FollowSymLinks + Options -Indexes +MultiViews +FollowSymLinks IndexOptions FancyIndexing # @@ -125,3 +125,13 @@ </VirtualHost> +# Include all *.conf files from /etc/apache2/conf.d/. +# +# This is mostly meant as a place for other RPM packages to drop in their +# configuration snippet. +# +# You can comment this out here if you want those bits include only in a +# certain virtual host, but not here. +# +Include /etc/apache2/conf.d/*.conf + diff -u /root/down/etc/apache2/httpd.conf /etc/apache2/httpd.conf --- /root/down/etc/apache2/httpd.conf 2013-07-31 14:33:35.000000000 +0200 +++ /etc/apache2/httpd.conf 2013-10-20 23:58:37.338070707 +0200 @@ -177,7 +177,8 @@ # in which case these default settings will be overridden for the # virtual host being defined. # -Include /etc/apache2/default-server.conf +#Include /etc/apache2/default-server.conf +Include /etc/apache2/default-vhost.conf # Another way to include your own files Hope that helps someone (at least it will help myself on re-installation someday, when I look for help in this forum ;-)) /Hannes
The next issue I had (or better: have) with mailman: In openSUSE 12.3 the mm_cfg.py is located under /usr/lib/mailman/Mailman instead of /etc/mailman (which is a packager fault to me, but nethertheless...), so I had to symlink /usr/lib/mailman/Mailman/mm_cfg.py to /etc/mailman, as the config file location is hardwired in ISPConfig3. While debugging this I stumbled upon some small errors in mailman_plugin.inc.php, see the patch Code: diff -wur /root/down/ispconfig3_install/server/conf/mm_cfg.py.master /root/down/ispconfig3_install.new/server/conf/mm_cfg.py.master --- /root/down/ispconfig3_install/server/conf/mm_cfg.py.master 2013-02-06 15:34:57.000000000 +0100 +++ /root/down/ispconfig3_install.new/server/conf/mm_cfg.py.master 2013-10-26 00:26:03.227157603 +0200 @@ -57,8 +57,8 @@ #------------------------------------------------------------- # If you change these, you have to configure your http server # accordingly (Alias and ScriptAlias directives in most httpds) -DEFAULT_URL_PATTERN = 'http://%s/cgi-bin/mailman/' -PRIVATE_ARCHIVE_URL = '/cgi-bin/mailman/private' +DEFAULT_URL_PATTERN = 'http://%s/mailman/' +PRIVATE_ARCHIVE_URL = '/mailman/private' IMAGE_LOGOS = '/images/mailman/' #------------------------------------------------------------- diff -wur /root/down/ispconfig3_install/server/plugins-available/mailman_plugin.inc.php /root/down/ispconfig3_install.new/server/plugins-available/mailman_plugin.inc.php --- /root/down/ispconfig3_install/server/plugins-available/mailman_plugin.inc.php 2013-03-26 13:42:12.000000000 +0100 +++ /root/down/ispconfig3_install.new/server/plugins-available/mailman_plugin.inc.php 2013-10-25 18:23:10.822813778 +0200 @@ -106,7 +106,7 @@ function update_config() { global $app, $conf; - copy($this->mailman_config_dir.'mm_cfg.py',$this->mailman_config_dir.'mm_cfg.py'); + copy($this->mailman_config_dir.'mm_cfg.py',$this->mailman_config_dir.'mm_cfg.py~'); // load the server configuration options $app->uses('getconf'); @@ -147,7 +147,7 @@ } $content = str_replace('{hostname}', $server_config['hostname'], $content); - $content = str_replace('{default_language}', $old_options['DEFAULT_SERVER_LANGUAGE'], $content); + $content = str_replace('{default_language}', $old_options['DEFAULT_SERVER_LANGUAGE'] ? $old_options['DEFAULT_SERVER_LANGUAGE'] : "'en'", $content); $content = str_replace('{virtual_domains}', $virtual_domains, $content); file_put_contents($this->mailman_config_dir."/mm_cfg.py", $content); The first one is only a cosmetic failure, the mm_cfg.py isn't backed up but copied to itself. The second one leads to a config file error as described in this post. Now, when I create a list named "test", the /etc/mailman/mm_cfp.py gets altered as expected, /var/lib/mailman/data/aliases and /var/lib/mailman/data/transport_mailman get populated and all looks fine, but: Code: Oct 25 18:59:52 idefix amavis[13622]: (13622-06) Passed CLEAN {RelayedInbound}, <[email protected]> -> <[email protected]>, Message-ID: <[email protected]>, mail_id: 085XpvNCRoj5, Hits: 0.729, size: 429, queued_as: 65D4F1A0754, 352 ms Oct 25 18:59:52 idefix postfix/smtp[26841]: 120A31A09C0: to=<[email protected]>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.41, delays=0.06/0/0/0.35, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 65D4F1A0754) Oct 25 18:59:52 idefix postfix/qmgr[9785]: 120A31A09C0: removed Oct 25 18:59:52 idefix postfix/local[26919]: 65D4F1A0754: to=<[email protected]>, relay=local, delay=0.07, delays=0.03/0/0/0.03, dsn=5.1.1, status=bounced (unknown user: "test") After some thinking this appears correct to me, as the transport for the mailman addresses got changed to local but theres no local test account. So I added hash:/var/lib/mailman/data/aliases to the alias_maps line in /etc/postfix/main.cf and then mails to the test list got accepted. For some reason (which I don't understand) there's an error regarding [email protected] in the log and the notice of pending messages to the list owner is not delivered. Code: Oct 25 23:27:16 idefix amavis[13621]: (13621-11) Passed CLEAN {RelayedInbound}, <[email protected]> -> <[email protected]>, Message-ID: <[email protected]>, mail_id: FmMSS6Jepce k, Hits: 0.729, size: 429, queued_as: C693B1A018A, 337 ms Oct 25 23:27:16 idefix postfix/smtp[6141]: 7AB511A0B51: to=<[email protected]>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.4, delays=0.06/0/0/0.34, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025) : 250 2.0.0 Ok: queued as C693B1A018A) Oct 25 23:27:16 idefix postfix/qmgr[5627]: 7AB511A0B51: removed Oct 25 23:27:16 idefix postfix/local[6146]: C693B1A018A: to=<[email protected]>, relay=local, delay=0.11, delays=0.05/0/0/0.06, dsn=2.0.0, status=sent (delivered to command: /usr/lib/mailman/mail/mailman post test ) Oct 25 23:27:16 idefix postfix/qmgr[5627]: C693B1A018A: removed Oct 25 23:27:18 idefix postfix/smtpd[6079]: connect from localhost[127.0.0.1] Oct 25 23:27:18 idefix postfix/smtpd[6079]: 0884F1A018A: client=localhost[127.0.0.1] Oct 25 23:27:18 idefix postfix/cleanup[6138]: 0884F1A018A: message-id=<[email protected]> Oct 25 23:27:18 idefix postfix/qmgr[5627]: 0884F1A018A: from=<[email protected]>, size=1187, nrcpt=1 (queue active) Oct 25 23:27:18 idefix postfix/smtpd[6079]: disconnect from localhost[127.0.0.1] Oct 25 23:27:18 idefix postfix/smtpd[6079]: connect from localhost[127.0.0.1] Oct 25 23:27:18 idefix postfix/smtpd[6079]: NOQUEUE: reject: RCPT from localhost[127.0.0.1]: 550 5.1.1 <[email protected]>: Recipient address rejected: User unknown in virtual mailbox table; from=<test-bounc [email protected]> to=<[email protected]> proto=ESMTP helo=<[144.76.174.240]> The test-owner alias is present, and a manually sent email to [email protected] gets delivered as well. Code: Oct 26 01:11:46 idefix amavis[13622]: (13622-15) Passed CLEAN {RelayedInbound}, <[email protected]> -> <[email protected]>, Message-ID: <[email protected]>, mail_id: VNfYkz1infid, Hits: -0.001, size: 435, queued_as: CE6D01A069B, 407 ms Oct 26 01:11:46 idefix postfix/smtp[4384]: 6CB851A0727: to=<[email protected]>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.48, delays=0.07/0/0/0.41, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as CE6D01A069B) Oct 26 01:11:46 idefix postfix/qmgr[4370]: 6CB851A0727: removed Oct 26 01:11:46 idefix postfix/local[4390]: CE6D01A069B: to=<[email protected]>, relay=local, delay=0.09, delays=0.03/0/0/0.06, dsn=2.0.0, status=sent (delivered to command: /usr/lib/mailman/mail/mailman owner test) Oct 26 01:11:46 idefix postfix/qmgr[4370]: CE6D01A069B: removed Can somebody point me to the my mistake, please? Why ISPC makes use of the transport_maps method as described here instead of the virtual_alias_maps method described e.g. here and there? Clueless, /Hannes
Oh, and by the way: when I create a list, the aliases and the virtual_mailman/transport_mailman files got altered, but when I delete a list, only the aliases file is cleaned up. The transport_mailman file stays unchanged until manual invocation of /usr/lib/mailman/bin/genaliases. Maybe this should called every time a list is deleted. /Hannes
Hi all, as I didn't made out the reason for using transport_maps+local transport instead of virtual_alias_maps+alias_maps, I modified the whole thing to use virtual_alias_maps: /etc/postfix/main.cf: use (virtual_)alias_maps instead of transport_maps Code: diff -wur /root/down/ispconfig3_install/install/tpl/opensuse_postfix.conf.master /root/down/ispconfig3_install.new/install/tpl/opensuse_postfix.conf.master --- /root/down/ispconfig3_install/install/tpl/opensuse_postfix.conf.master 2013-07-12 16:56:16.000000000 +0200 +++ /root/down/ispconfig3_install.new/install/tpl/opensuse_postfix.conf.master 2013-10-27 02:42:09.594540060 +0100 @@ -1,5 +1,6 @@ virtual_alias_domains = -virtual_alias_maps = proxy:mysql:{config_dir}/mysql-virtual_forwardings.cf, proxy:mysql:{config_dir}/mysql-virtual_email2email.cf +alias_maps = hash:/etc/aliases, hash:/var/lib/mailman/data/aliases +virtual_alias_maps = hash:/var/lib/mailman/data/virtual-mailman, proxy:mysql:{config_dir}/mysql-virtual_forwardings.cf, proxy:mysql:{config_dir}/mysql-virtual_email2email.cf virtual_mailbox_domains = proxy:mysql:{config_dir}/mysql-virtual_domains.cf virtual_mailbox_maps = proxy:mysql:{config_dir}/mysql-virtual_mailboxes.cf virtual_mailbox_base = {vmail_mailbox_base} @@ -13,7 +14,7 @@ smtpd_tls_security_level = may smtpd_tls_cert_file = {config_dir}/smtpd.cert smtpd_tls_key_file = {config_dir}/smtpd.key -transport_maps = hash:/var/lib/mailman/data/transport-mailman, proxy:mysql:{config_dir}/mysql-virtual_transports.cf +transport_maps = proxy:mysql:{config_dir}/mysql-virtual_transports.cf relay_domains = mysql:{config_dir}/mysql-virtual_relaydomains.cf relay_recipient_maps = mysql:{config_dir}/mysql-virtual_relayrecipientmaps.cf proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps mm_cfg.py: added template for add_virtualhost, removed POSTFIX_MAP_CMD Code: diff -wur /root/down/ispconfig3_install/server/conf/mm_cfg.py.master /root/down/ispconfig3_install.new/server/conf/mm_cfg.py.master --- /root/down/ispconfig3_install/server/conf/mm_cfg.py.master 2013-02-06 15:34:57.000000000 +0100 +++ /root/down/ispconfig3_install.new/server/conf/mm_cfg.py.master 2013-10-27 03:11:25.578848251 +0100 @@ -57,8 +57,8 @@ #------------------------------------------------------------- # If you change these, you have to configure your http server # accordingly (Alias and ScriptAlias directives in most httpds) -DEFAULT_URL_PATTERN = 'http://%s/cgi-bin/mailman/' -PRIVATE_ARCHIVE_URL = '/cgi-bin/mailman/private' +DEFAULT_URL_PATTERN = 'http://%s/mailman/' +PRIVATE_ARCHIVE_URL = '/mailman/private' IMAGE_LOGOS = '/images/mailman/' #------------------------------------------------------------- @@ -70,6 +70,7 @@ #------------------------------------------------------------- # Required when setting any of its arguments. add_virtualhost(DEFAULT_URL_HOST, DEFAULT_EMAIL_HOST) +{add_virtualhosts} #------------------------------------------------------------- # The default language for this server. @@ -102,7 +103,7 @@ # http://www.jamesh.id.au/articles/mailman-spamassassin/ # GLOBAL_PIPELINE.insert(1, 'SpamAssassin') -POSTFIX_MAP_CMD = '/etc/mailman/virtual_to_transport.sh' +#POSTFIX_MAP_CMD = '/etc/mailman/virtual_to_transport.sh' # Note - if you're looking for something that is imported from mm_cfg, but you # didn't find it above, it's probably in /usr/lib/mailman/Mailman/Defaults.py. \ No newline at end of file mailman_plugin.inc.php: added template handling, added genaliases invocation, fixed two small bugs Code: diff -wur /root/down/ispconfig3_install/server/plugins-available/mailman_plugin.inc.php /root/down/ispconfig3_install.new/server/plugins-available/mailman_plugin.inc.php --- /root/down/ispconfig3_install/server/plugins-available/mailman_plugin.inc.php 2013-03-26 13:42:12.000000000 +0100 +++ /root/down/ispconfig3_install.new/server/plugins-available/mailman_plugin.inc.php 2013-10-27 03:35:48.131793363 +0100 @@ -75,6 +75,7 @@ exec("nohup /usr/lib/mailman/bin/newlist -u ".escapeshellcmd($data["new"]["domain"])." -e ".escapeshellcmd($data["new"]["domain"])." ".escapeshellcmd($data["new"]["listname"])." ".escapeshellcmd($data["new"]["email"])." ".escapeshellcmd($data["new"]["password"])." >/dev/null 2>&1 &"); if(is_file('/var/lib/mailman/data/virtual-mailman')) exec('postmap /var/lib/mailman/data/virtual-mailman'); + exec("nohup /usr/lib/mailman/bin/genaliases >/dev/null 2>&1 &"); exec('nohup '.$conf['init_scripts'] . '/' . 'mailman reload >/dev/null 2>&1 &'); $app->db->query("UPDATE mail_mailinglist SET password = '' WHERE mailinglist_id = ".$app->db->quote($data["new"]['mailinglist_id'])); @@ -98,7 +99,7 @@ $this->update_config(); exec("nohup /usr/lib/mailman/bin/rmlist -a ".escapeshellcmd($data["old"]["listname"])." >/dev/null 2>&1 &"); - + exec("nohup /usr/lib/mailman/bin/genaliases >/dev/null 2>&1 &"); exec('nohup '.$conf['init_scripts'] . '/' . 'mailman reload >/dev/null 2>&1 &'); } @@ -106,7 +107,7 @@ function update_config() { global $app, $conf; - copy($this->mailman_config_dir.'mm_cfg.py',$this->mailman_config_dir.'mm_cfg.py'); + copy($this->mailman_config_dir.'mm_cfg.py',$this->mailman_config_dir.'mm_cfg.py~'); // load the server configuration options $app->uses('getconf'); @@ -138,16 +139,19 @@ // create virtual_domains list $domainAll = $app->db->queryAllRecords("SELECT domain FROM mail_mailinglist GROUP BY domain"); $virtual_domains = ''; + $virtual_hosts = ''; foreach($domainAll as $domain) { if ($domainAll[0]['domain'] == $domain['domain']) $virtual_domains .= "'".$domain['domain']."'"; else $virtual_domains .= ", '".$domain['domain']."'"; + $virtual_hosts .= "add_virtualhost('www." . $domain['domain'] . "', '" . $domain['domain'] . "')\n"; } $content = str_replace('{hostname}', $server_config['hostname'], $content); - $content = str_replace('{default_language}', $old_options['DEFAULT_SERVER_LANGUAGE'], $content); + $content = str_replace('{default_language}', $old_options['DEFAULT_SERVER_LANGUAGE'] ? $old_options['DEFAULT_SERVER_LANGUAGE'] : "'en'", $content); + $content = str_replace('{add_virtualhosts}', $virtual_hosts, $content); $content = str_replace('{virtual_domains}', $virtual_domains, $content); file_put_contents($this->mailman_config_dir."/mm_cfg.py", $content); Seems to work as expected. The only thing that has to be done is to implement a check for <listname[-(admin|bounces|etc)>@<virtualdom.ain> against mailboxes and aliases in this virtualdomain. At the moment one could create a list named "test" and an email account "test" (or - maybe difficultier to debug - "test-owner") in the same domain. /Hannes
Next issue: Due to an incorrect assumption the mail quota usage was not displayed correctly. The "storage" and "messages" values are not always in the same order in the .quotausage file, so in my installation the parser read the messages count instead of the mailstorage size. See patch: Code: diff -wur /root/down/ispconfig3_install/server/lib/classes/monitor_tools.inc.php /root/down/ispconfig3_install.new/server/lib/classes/monitor_tools.inc.php --- /root/down/ispconfig3_install/server/lib/classes/monitor_tools.inc.php 2013-07-17 19:24:22.000000000 +0200 +++ /root/down/ispconfig3_install.new/server/lib/classes/monitor_tools.inc.php 2013-10-28 16:39:35.550046411 +0100 @@ -250,7 +250,10 @@ $filename = $mb['maildir'].'/.quotausage'; if(file_exists($filename) && !is_link($filename)) { $quotafile = file($filename); - $data[$email]['used'] = trim($quotafile['1']); + preg_match('/storage.*?([0-9]+)/s', implode('',$quotafile), $storage_value); + $data[$email]['used'] = $storage_value[1]; + $app->log("Mail storage $email: " . $storage_value[1], LOGLEVEL_DEBUG); unset($quotafile); } else { exec('du -s '.escapeshellcmd($mb['maildir']),$out); /Hannes
@Till: as I don't wanna talk to myself only: got the above mentioned issues addressed in 3.0.5.4? How could I possibly contribute? Thanks,
Please open up a bugreport in our bugtracker http://bugtracker.ispconfig.org for the issue and post your patch there. I will review the patch then and merge it into our git stable branch so it gets included in ispconfig 3.0.5.4
As I found out today the patch isn't included in 3.0.5.4 yet, why? What can I do to help getting this into the stable release? Regards,
We have GIT server no: http://git.ispconfig.org/explore When you sign up there, you can fork the master branch, implement your changes and then submit a merge request.