FrontEnd GNU/NONGNU host redirection
Savannah handles three types of hosts redirection:
- Shortcut URL to full URL (e.g.
*.sv.gnu.org
=>*.savannah.gnu.org
). *.gnu.org
<=>*.nongnu.org
, depending on group type.- automatic-login to both
savannah.gnu.org
andsavannah.nongnu.org
- attachment requests from old URLs to dedicated domain
(
savannah.gnu.org/file/*
=>file.savannah.gnu.org/file/*
,savannah.gnu.org/submission-uploads/
=>file.savannah.gnu.org/submission-uploads/
) and non-file requests fromfile.savannah.*.org
to the original domain.
Shortcut URL redirection
Shortcurt URL redirection (.e.g *.sv.gnu.org
=> *.savannah.gnu.org
)
is handled entirely in the Apache configuration.
This would've been simple, if it were't for two complications:
For HTTP, all URLs should be redirected as-is with full URI (e.g. http://sv.gnu.org/p/coreutils should redirect to http://savannah.gnu.org/p/coreutils, not just to http://savannah.gnu.org) EXCEPT the
.well-known
directory, which must not be redirected because of the use of Let's-Encrypt certboot (i.e. http://sv.gnu.org/.well-known/XXX must be valid and not redirected). See https for details about the certbot configuration.For HTTPS, slightly different configuration is set needed on whether it's gnu or nongnu domain, while still requiring that https://sv.gnu.org/p/coreutils redirects to the full https://savannah.gnu.org/p/coreutils.
The FrontEndDevelopmentSite currently uses the following method:
<VirtualHost *:80>
ServerName jsmith.frontend0.savannah.gnu.org
ServerAlias jsmith.frontend0.savannah.nongnu.org
ServerAlias jsmith.frontend0.sv.gnu.org
ServerAlias jsmith.frontend0.sv.nongnu.org
<If "%{HTTP_HOST} == 'jsmith.frontend0.savannah.gnu.org' && %{REQUEST_URI} !~ /\.well-known/" >
RedirectMatch "(.*)" https://jsmith.frontend0.savannah.gnu.org$1
</If>
<ElseIf "%{HTTP_HOST} == 'jsmith.frontend0.savannah.gnu.org' && %{REQUEST_URI} !~ /\.well-known/" >
RedirectMatch "(.*)" https://jsmith.frontend0.savannah.nongnu.org$1
</ElseIf>
<ElseIf "%{HTTP_HOST} == 'jsmith.frontend0.sv.gnu.org' && %{REQUEST_URI} !~ /\.well-known/" >
RedirectMatch "(.*)" https://jsmith.frontend0.savannah.gnu.org$1
</ElseIf>
<ElseIf "%{HTTP_HOST} == 'jsmith.frontend0.sv.nongnu.org' && %{REQUEST_URI} !~ /\.well-known/" >
RedirectMatch "(.*)" https://jsmith.frontend0.savannah.nongnu.org$1
</ElseIf>
Include sites-available/certbot-wellknown.inc
</VirtualHost>
<VirtualHost *:443>
ServerAlias jsmith.frontend0.sv.gnu.org
ServerAlias jsmith.frontend0.sv.nongnu.org
ServerName jsmith.frontend0.savannah.gnu.org
ServerAlias jsmith.frontend0.savannah.nongnu.org
<If "%{HTTP_HOST} == 'jsmith.frontend0.savannah.gnu.org'">
SetEnv SAVANE_CONF /home/jsmith/savannah/etc/savane/
</If>
<ElseIf "%{HTTP_HOST} == 'jsmith.frontend0.savannah.nongnu.org'">
SetEnv SAVANE_CONF /home/jsmith/savannah/etc/savane/nongnu-conf/
</ElseIf>
# If the '.sv.gnu.org' shortcut is used, redirect to the full
# '.savannah.gnu.org' URL.
<ElseIf "%{HTTP_HOST} == 'jsmith.frontend0.sv.gnu.org'">
RedirectMatch "(.*)" https://jsmith.frontend0.savannah.gnu.org$1
</ElseIf>
<ElseIf "%{HTTP_HOST} == 'jsmith.frontend0.sv.nongnu.org'">
RedirectMatch "(.*)" https://jsmith.frontend0.savannah.nongnu.org$1
</ElseIf>
[...]
</VirtualHost>
Note that certbot's configuration uses Alias
, which has lower precedence
in Apache than RedirectMatch
- requiring some fiddling with the conditions.
FIXME: If there's a better configuration, please write to savannah-hackers-public@gnu.org .
FIXME: Document the Apache setup for the production website, which use:
sites-enabled/000-vhosts-gnu.org.conf -> ../sites-available/vhosts-gnu.org
sites-enabled/vhosts-nongnu.org.conf -> ../sites-available/vhosts-nongnu.org
# in sites-available/vhosts-gnu.org:
<VirtualHost *:80>
Include sites-available/sv.gnu.inc
</VirtualHost>
<VirtualHost *:443>
Include sites-available/sv.gnu.inc
</VirtualHost>
<VirtualHost *:443>
ServerName frontend0.savannah.gnu.org
Include sites-available/sv.inc
</VirtualHost>
# in sites-available/vhosts-nongnu.org:
<VirtualHost *:80>
Include sites-available/sv.nongnu.inc
</VirtualHost>
<VirtualHost *:443>
Include sites-available/sv.nongnu.inc
</VirtualHost>
<VirtualHost *:443>
ServerName frontend0.savannah.nongnu.org
SetEnv SV_LOCAL_INC_PREFIX /etc/savane/nongnu-conf
Include sites-available/sv.inc
</VirtualHost>
# in sites-available/sv.gnu.inc:
ServerName savannah.gnu.org
Include sites-available/sv.inc
# in sites-available/sv.nongnu.org:
ServerName savannah.nongnu.org
SetEnv SV_LOCAL_INC_PREFIX /etc/savane/nongnu-conf
Include sites-available/sv.inc
GNU/NONGNU redirection
gnu/nongnu redirection is handled entirely in the PHP code, based on whether the viewed group belongs in GNU or not (sometimes referred to as 'brother' site in the code/config files).
Example: when users visit https://savannah.nongnu.org/projects/coreutils they are redirected to https://savannah.gnu.org/projects/coreutils because coreutils is an official GNU package.
Enabling/Disabling redirection
In .savane.conf.php
, setting the boolean variable
$sys_debug_nobasehost
to true
disables redirection completely -
useful for FrontEndDevelopmentSite.
Group-based redirection
When a page is visited (if it relates to a hosted group), the
function $project->getTypeBaseHost()
is called and returns the host
that is relevant to the viewed group (based on the group type).
The values on the production site are:
mysql> select type_id, name, base_host from group_type ;
+---------+------------------------------------+---------------------+
| type_id | name | base_host |
+---------+------------------------------------+---------------------+
| 1 | Official GNU software | savannah.gnu.org |
| 2 | non-GNU software and documentation | savannah.nongnu.org |
| 3 | www.gnu.org portions | savannah.gnu.org |
| 4 | GUG | savannah.nongnu.org |
| 6 | www.gnu.org translation teams | savannah.gnu.org |
+---------+------------------------------------+---------------------+
5 rows in set (0.00 sec)
Meaning: if redirection is enabled on a development site, these values will cause redirection to the real website.
To test redirection on a FrontEndDevelopmentSite, do the following
(on a development database copy, never on the real database savane
):
mysql> update group_type set base_host = "jsmith.frontend0.savannah.gnu.org" where type_id in (1,3,6);
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql> update group_type set base_host = "jsmith.frontend0.savannah.nongnu.org" where type_id in (2,4);
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> select type_id, name, base_host from group_type ;
+---------+------------------------------------+--------------------------------------+
| type_id | name | base_host |
+---------+------------------------------------+--------------------------------------+
| 1 | Official GNU software | jsmith.frontend0.savannah.gnu.org |
| 2 | non-GNU software and documentation | jsmith.frontend0.savannah.nongnu.org |
| 3 | www.gnu.org portions | jsmith.frontend0.savannah.gnu.org |
| 4 | GUG | jsmith.frontend0.savannah.nongnu.org |
| 6 | www.gnu.org translation teams | jsmith.frontend0.savannah.gnu.org |
+---------+------------------------------------+--------------------------------------+
5 rows in set (0.00 sec)
Then set $sys_debug_nobasehost=false;
the development .savane.conf.php
file.
PHP Code
The variable $sys_debug_nobasehost
is mentioned in the following files:
in ./frontend/php/include/init.php
:
# if we are at wrong url, redirect
if (!$sys_debug_nobasehost && strcasecmp($_SERVER['HTTP_HOST"], $project->getTypeBaseHost()) != 0 && $project->getTypeBaseHost())
{
header ("Location: http".(session_issecure()?'s":'")."://".$project->getTypeBaseHost().$_SERVER['PHP_SELF"]);
exit;
}
in ./frontend/php/include/project_home/php
:
if (strcasecmp($_SERVER['HTTP_HOST"], $project->getTypeBaseHost()) != 0 && $project->getTypeBaseHost())
{
header ('Location: http".(session_issecure()?'s":'").'://".$project->getTypeBaseHost().$_SERVER["REQUEST_URI"]);
exit;
}
Auto-login to 'brother' site
When a user visits the login page on https://savannah.gnu.org/account/login.php, there's is a check-box at the bottom of the page asking for "Login also in savannah.nongnu.org".
This is called a "brother" site in the code and config files. It is implemented using several HTTP redirects from one site to the other (e.g from the default 'savannah.gnu.org' to 'savannah.nongnu.org') sending hashed session IDs back and forth (counting on the fact that both sites run on the same physical server and share PHP session cookies).
In /etc/savane/.savane.conf.php
there are these two variables:
$sys_default_domain="savannah.gnu.org";
$sys_brother_domain="savannah.nongnu.org";
$sys_incdir="/etc/savane/content/gnu-content";
In the correspnding /etc/savane/nongnu-conf/.savane.conf.php
the
default/brother hosts are swapped:
$sys_default_domain="frontend0.savannah.nongnu.org";
$sys_https_host="$sys_default_domain";
$sys_brother_domain="frontend0.savannah.gnu.org";
$sys_incdir="/etc/savane/content/nongnu-content";
If using a development site FrontEndDevelopmentSite,
use the following in /home/jsmith/savannah/etc/savane/.savane.conf.php
:
$sys_default_domain="jsmith.frontend0.savannah.gnu.org";
$sys_brother_domain="jsmith.frontend0.savannah.nongnu.org";
$sys_incdir="/home/jsmith/savannah/etc/savane/content/gnu-content";
and in /home/jsmith/savannah/etc/savane/nongnu-conf/.savane.conf.php
:
$sys_default_domain="jsmith.frontend0.savannah.nongnu.org";
$sys_https_host="$sys_default_domain";
$sys_brother_domain="jsmith.frontend0.savannah.gnu.org";
$sys_incdir="/home/jsmith/savannah/etc/savane/content/nongnu-content";
The Apache configuration must be set appropriately for each domain.
See SAVANE_CONF
settings above.
NOTE:
If the "login to [brother] set" checkbox is set,
Savannah will do the redirection even if the variable is set
($sys_debug_nobasehost=true
).
If you forget to update the settings in nongnu-conf/.savane.conf.php
,
you might get redirected to the real website (e.g. savannah.nongnu.org
),
which will not only confuse things, but will also cause troubles
with cookie authentication (you'll see an error message saying
"Savane thinks your cookies are not activated for XXX" from login.php
).
The 'brother' login sequences is used in two files:
./frontend/php/account/login.php
and ./frontend/php/account/su.php
(su
implements "become superuser" feature for admins).
The gist is:
After successful login to
savannah.gnu.org
,login.php
will redirect to: https://savannah.NONGNU.org/account/login.php?session_uid=94790&session_hash=XXXXXXXXXX&cookie_for_a_year=&from_brother=1&login=1&stay_in_ssl=1&brotherhood=1&uri=%2Flogin.php
(this time called on hostsavannah.nongnu.org
) will see that$from_brother=1
, and will set the cookie/session for this domain as well, then redirect back tosavannah.gnu.org/
.
File redirection
Since July 2020, Savannah serves user-supplied files from a separate domain for security reasons. Old URLs are redirected to that domain, non-file requests are redirected to the main domain.
ServerAlias file.savannah.gnu.org
<If "%{HTTP_HOST} == 'savannah.gnu.org'">
RedirectPermanent /submissions_uploads/ \
https://file.savannah.gnu.org/submissions_uploads/
RedirectPermanent /file https://file.savannah.gnu.org/file
</If>
<If "%{REQUEST_URI} =~ m#^/((submissions_uploads/)|(file((/.*)?)$))#">
# Empty section: the server will redirect when %{REQUEST_URI}
# does _not_ match the above regular expression.
</If>
<ElseIf "%{HTTP_HOST} == 'file.savannah.gnu.org'">
RedirectPermanent / https://savannah.gnu.org/
</ElseIf>
Likewise, for savanah.nongnu.org.