1#!/usr/bin/env perl 2 3# BEGIN BPS TAGGED BLOCK {{{ 4# 5# COPYRIGHT: 6# 7# This software is Copyright (c) 1996-2021 Best Practical Solutions, LLC 8# <sales@bestpractical.com> 9# 10# (Except where explicitly superseded by other copyright notices) 11# 12# 13# LICENSE: 14# 15# This work is made available to you under the terms of Version 2 of 16# the GNU General Public License. A copy of that license should have 17# been provided with this software, but in any event can be snarfed 18# from www.gnu.org. 19# 20# This work is distributed in the hope that it will be useful, but 21# WITHOUT ANY WARRANTY; without even the implied warranty of 22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23# General Public License for more details. 24# 25# You should have received a copy of the GNU General Public License 26# along with this program; if not, write to the Free Software 27# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 28# 02110-1301 or visit their web page on the internet at 29# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. 30# 31# 32# CONTRIBUTION SUBMISSION POLICY: 33# 34# (The following paragraph is not intended to limit the rights granted 35# to you to modify and distribute this software under the terms of 36# the GNU General Public License and is only of importance to you if 37# you choose to contribute your changes and enhancements to the 38# community by submitting them to Best Practical Solutions, LLC.) 39# 40# By intentionally submitting any modifications, corrections or 41# derivatives to this work, or any other work intended for use with 42# Request Tracker, to Best Practical Solutions, LLC, you confirm that 43# you are the copyright holder for those contributions and you grant 44# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, 45# royalty-free, perpetual, license to use, copy, create derivative 46# works based on those contributions, and sublicense and distribute 47# those contributions and any derivatives thereof. 48# 49# END BPS TAGGED BLOCK }}} 50use strict; 51use warnings; 52 53use Getopt::Long; 54use FindBin; 55use Pod::Usage; 56use File::Spec::Functions qw(rel2abs); 57 58my %opt = ( 59 root => ($ENV{RTHOME} || "/opt/rt4"), 60 61 fcgid => 0, 62 fastcgi => 0, 63 perl => 0, 64 65 modules => "/usr/lib/apache2/modules", 66); 67 68GetOptions( \%opt, 69 "root=s", 70 71 "rt3|3!", 72 73 "fcgid!", 74 "fastcgi!", 75 "perl!", 76 77 "port|p=i", 78 "ssl:i", 79 "single|X", 80 "auth|A:s", 81 82 "modules=s", 83 84 "help|h|?", 85) or pod2usage( 1 ); 86pod2usage( {verbose => 2} ) if $opt{help}; 87 88# All paths must be absolute 89$opt{$_} = rel2abs($opt{$_}) 90 for qw(root modules); 91 92# Determine what module to use 93my $mod; 94if ($opt{fcgid} + $opt{fastcgi} + $opt{perl} > 1) { 95 die "Can only supply one of fcgid, fastcgi, or perl\n"; 96} elsif ($opt{fcgid} + $opt{fastcgi} + $opt{perl} == 0) { 97 my @guess = qw(fastcgi fcgid perl); 98 @guess = grep {-f "$opt{modules}/mod_$_.so"} @guess; 99 die "Neither mod_fcgid, mod_fastcgi, nor mod_perl are installed; aborting\n" 100 unless @guess; 101 warn "No deployment given -- assuming mod_$guess[0] deployment\n"; 102 $mod = $guess[0]; 103} else { 104 $mod = (grep {$opt{$_}} qw(fastcgi fcgid perl))[0]; 105} 106 107# Sanity check that the root contains an RT install 108die "$opt{root} doesn't look like an RT install\n" 109 unless -e "$opt{root}/lib/RT.pm"; 110 111# Detect if we are actually rt3 112if (not -e "$opt{root}/sbin/rt-server.fcgi" 113 and -e "$opt{root}/bin/mason_handler.fcgi") { 114 $opt{rt3}++; 115 warn "RT3 install detected!\n"; 116} 117 118# Parse etc/RT_SiteConfig.pm for the default port 119my $RTCONF; 120$opt{port} ||= parseconf( "WebPort" ); 121unless ($opt{port}) { 122 warn "Defaulting to port 8888\n"; 123 $opt{port} = 8888; 124} 125 126# Set ssl port if they want it but didn't provide a number 127$opt{ssl} = 4430 if defined $opt{ssl} and not $opt{ssl}; 128 129# Default auth to on if they set $WebRemoteUserAuth 130$opt{auth} = '' if not exists $opt{auth} and parseconf( "WebRemoteUserAuth" ); 131 132# Set an auth path if they want it but didn't pass a path 133if (defined $opt{auth} and not $opt{auth}) { 134 $opt{auth} = "$opt{root}/var/htpasswd"; 135 unless (-f $opt{auth}) { 136 open(my $fh, ">", $opt{auth}) or die "Can't create default htpasswd: $!"; 137 print $fh 'root:$apr1$TZA4Y0DL$DS5ZhDH8QrhB.uAtvNJmh.' . "\n"; 138 close $fh or die "Can't create default htpasswd: $!"; 139 } 140} elsif ($opt{auth} and not -f $opt{auth}) { 141 die "Can't read htpasswd file $opt{auth}!"; 142} 143 144# Parse out the WebPath 145my $path = parseconf( "WebPath" ) || ""; 146 147my $template = join("", <DATA>); 148$template =~ s/\$PORT/$opt{port}/g; 149$template =~ s!\$PATH/!$path/!g; 150$template =~ s!\$PATH!$path || "/"!ge; 151$template =~ s/\$SSL/$opt{ssl} || 0/ge; 152$template =~ s/\$AUTH/$opt{auth}/ge; 153$template =~ s/\$RTHOME/$opt{root}/g; 154$template =~ s/\$MODULES/$opt{modules}/g; 155$template =~ s/\$TOOLS/$FindBin::Bin/g; 156$template =~ s/\$PROCESSES/$opt{single} ? 1 : 3/ge; 157 158my $conf = "$opt{root}/var/apache.conf"; 159open(CONF, ">", $conf) 160 or die "Can't write $conf: $!"; 161print CONF $template; 162close CONF; 163 164my @opts = ("-f", $conf, "-D" . uc($mod) ); 165push @opts, "-DSSL" if $opt{ssl}; 166push @opts, "-DRT3" if $opt{rt3}; 167push @opts, "-DSINGLE" if $opt{single}; 168push @opts, "-DREDIRECT" if $path; 169push @opts, "-DAUTH" if $opt{auth}; 170 171# Wait for a previous run to terminate 172if ( open( PIDFILE, "<", "$opt{root}/var/apache2.pid") ) { 173 my $pid = <PIDFILE>; 174 chomp $pid; 175 close PIDFILE; 176 if ($pid and kill 0, $pid) { 177 warn "Waiting for previous run (pid $pid) to finish...\n"; 178 sleep 1 while kill 0, $pid; 179 } 180} 181 182# Clean out the log in preparation 183my $log = "$opt{root}/var/log/apache-error.log"; 184unlink($log); 185 186# Start 'er up 187warn "Starting apache server on http://localhost:$opt{port}$path/" 188 . ($opt{ssl} ? " and https://localhost:$opt{ssl}$path/" : "") . "\n"; 189!system("apache2", @opts, "-k", "start") 190 or die "Can't exec apache2: $@"; 191# Ignore the return value, as we expect it to be ^C'd 192system("tail", "-f", $log); 193warn "Shutting down apache...\n"; 194!system("apache2", @opts, "-k", "stop") 195 or die "Can't exec apache2: $@"; 196 197 198sub parseconf { 199 my ($optname) = @_; 200 # We're going to be evil, and try to parse the config 201 unless (defined $RTCONF) { 202 unless ( open(CONF, "<", "$opt{root}/etc/RT_SiteConfig.pm") ) { 203 warn "Can't open $opt{root}/etc/RT_SiteConfig.pm: $!\n"; 204 $RTCONF = ""; 205 return; 206 } 207 $RTCONF = join("", <CONF>); 208 close CONF; 209 } 210 211 return unless $RTCONF =~ /^\s*Set\(\s*\$$optname\s*(?:,|=>)\s*['"]?(.*?)['"]?\s*\)/m; 212 return $1; 213} 214 215=head1 NAME 216 217rt-apache - Wrapper to start Apache running RT 218 219=head1 DESCRIPTION 220 221This script exists to make it easier to run RT under Apache for testing. 222It is not intended as a way to deploy RT, or to provide example Apache 223configuration for RT. For instructions on how to deploy RT with Apache, 224please read the provided F<docs/web_deployment.pod> file. 225 226Running this script will start F<apache2> with a custom-built 227configuration file, built based on command-line options and the contents 228of your F<RT_SiteConfig.pm>. It will work with either RT 3.8.x or RT 2294.0.x. As it is primarily for simple testing, it runs Apache as the 230current user. 231 232=head1 OPTIONS 233 234C<rt-apache> will parse your F<RT_SiteConfig.pm> for its C<WebPath> and 235C<WebPort> configuration, and adjust its defaults accordingly. 236 237=over 238 239=item --root B<path> 240 241The path to the RT install to serve. This defaults to the C<RTHOME> 242environment variable, or C</opt/rt4>. 243 244=item --fastcgi, --fcgid, --perl 245 246Determines the Apache module which is used. By default, the first one 247of that list which exists will be used. See also L</--modules>. 248 249=item --port B<number>, -p 250 251Choses the port to listen on. By default, this is parsed from the 252F<RT_SiteConfig.pm>, and falling back to 8888. 253 254=item --ssl [B<number>] 255 256Also listens on the provided port with HTTPS, using a self-signed 257certificate for C<localhost>. If the port number is not specified, 258defaults to port 4430. 259 260=item --auth [F</path/to/htpasswd>], -A 261 262Turns on HTTP Basic Authentication; this is done automatically if 263C<$WebRemoteUserAuth> is set in the F<RT_SiteConfig.pm>. The provided 264path should be to a F<htpasswd> file; if not given, defaults to a file 265containing only user C<root> with password C<password>. 266 267=item --single, -X 268 269Run only one process or thread, for ease of debugging. 270 271=item --rt3, -3 272 273Declares that the RT install in question is RT 3.8.x. C<rt-apache> can 274usually detect this for you, however. 275 276=item --modules B<path> 277 278The path to the Apache2 modules directory, which is expected to contain 279at least one of F<mod_fcgid.so>, F<mod_fastcgi.so>, or F<mod_perl.so>. 280Defaults to F</usr/lib/apache2/modules>. 281 282=back 283 284=cut 285 286__DATA__ 287Listen $PORT 288<IfDefine SSL> 289 Listen $SSL 290</IfDefine> 291 292ServerName localhost 293ServerRoot $RTHOME/var 294PidFile $RTHOME/var/apache2.pid 295<IfVersion < 2.4> 296 LockFile $RTHOME/var/apache2.lock 297</IfVersion> 298ServerAdmin root@localhost 299 300<IfVersion >= 2.4> 301 LoadModule mpm_prefork_module $MODULES/mod_mpm_prefork.so 302 LoadModule authz_core_module $MODULES/mod_authz_core.so 303</IfVersion> 304LoadModule authz_host_module $MODULES/mod_authz_host.so 305LoadModule env_module $MODULES/mod_env.so 306LoadModule alias_module $MODULES/mod_alias.so 307LoadModule mime_module $MODULES/mod_mime.so 308TypesConfig $TOOLS/mime.types 309 310<IfDefine SINGLE> 311 <IfModule mpm_prefork_module> 312 StartServers 1 313 MinSpareServers 1 314 MaxSpareServers 1 315 MaxClients 1 316 MaxRequestsPerChild 0 317 </IfModule> 318 319 <IfModule mpm_worker_module> 320 StartServers 1 321 MinSpareThreads 1 322 MaxSpareThreads 1 323 ThreadLimit 1 324 ThreadsPerChild 1 325 MaxClients 1 326 MaxRequestsPerChild 0 327 </IfModule> 328</IfDefine> 329 330<IfDefine PERL> 331 LoadModule perl_module $MODULES/mod_perl.so 332</IfDefine> 333<IfDefine FASTCGI> 334 LoadModule fastcgi_module $MODULES/mod_fastcgi.so 335</IfDefine> 336<IfDefine FCGID> 337 LoadModule fcgid_module $MODULES/mod_fcgid.so 338</IfDefine> 339<IfDefine SSL> 340 LoadModule ssl_module $MODULES/mod_ssl.so 341 <IfVersion >= 2.4> 342 LoadModule socache_shmcb_module $MODULES/mod_socache_shmcb.so 343 </IfVersion> 344</IfDefine> 345 346<IfModule !log_config_module> 347 LoadModule log_config_module $MODULES/mod_log_config.so 348</IfModule> 349ErrorLog "$RTHOME/var/log/apache-error.log" 350TransferLog "$RTHOME/var/log/apache-access.log" 351LogLevel notice 352 353<Directory /> 354 Options FollowSymLinks 355 AllowOverride None 356 <IfVersion >= 2.4> 357 Require all denied 358 </IfVersion> 359 <IfVersion < 2.4> 360 Order deny,allow 361 Deny from all 362 </IfVersion> 363</Directory> 364 365AddDefaultCharset UTF-8 366 367<IfDefine REDIRECT> 368 LoadModule rewrite_module $MODULES/mod_rewrite.so 369 RewriteEngine on 370 RewriteRule ^(?!\Q$PATH\E) - [R=404] 371</IfDefine> 372 373<IfDefine AUTH> 374 <IfVersion >= 2.4> 375 LoadModule authn_core_module $MODULES/mod_authn_core.so 376 </IfVersion> 377 LoadModule auth_basic_module $MODULES/mod_auth_basic.so 378 LoadModule authn_file_module $MODULES/mod_authn_file.so 379 LoadModule authz_user_module $MODULES/mod_authz_user.so 380 <Location $PATH> 381 Require valid-user 382 AuthType basic 383 AuthName "RT access" 384 AuthBasicProvider file 385 AuthUserFile $AUTH 386 </Location> 387 <Location $PATH/REST/1.0/NoAuth/mail-gateway> 388 <IfVersion >= 2.4> 389 Require local 390 </IfVersion> 391 <IfVersion < 2.4> 392 Order deny,allow 393 Deny from all 394 Allow from localhost 395 Satisfy any 396 </IfVersion> 397 </Location> 398</IfDefine> 399<IfDefine !AUTH> 400 <Location $PATH> 401 <IfVersion >= 2.4> 402 Require all granted 403 </IfVersion> 404 <IfVersion < 2.4> 405 Order allow,deny 406 Allow from all 407 </IfVersion> 408 </Location> 409</IfDefine> 410 411<IfDefine !RT3> 412########## 4.0 mod_perl 413<IfDefine PERL> 414 PerlSetEnv RT_SITE_CONFIG $RTHOME/etc/RT_SiteConfig.pm 415 <Location $PATH> 416 SetHandler modperl 417 PerlResponseHandler Plack::Handler::Apache2 418 PerlSetVar psgi_app $RTHOME/sbin/rt-server 419 </Location> 420 <Perl> 421 use Plack::Handler::Apache2; 422 Plack::Handler::Apache2->preload("$RTHOME/sbin/rt-server"); 423 </Perl> 424</IfDefine> 425 426########## 4.0 mod_fastcgi 427<IfDefine FASTCGI> 428 FastCgiIpcDir $RTHOME/var 429 FastCgiServer $RTHOME/sbin/rt-server.fcgi -processes $PROCESSES -idle-timeout 300 430 ScriptAlias $PATH $RTHOME/sbin/rt-server.fcgi/ 431 <Location $PATH> 432 Options +ExecCGI 433 AddHandler fastcgi-script fcgi 434 </Location> 435</IfDefine> 436 437########## 4.0 mod_fcgid 438<IfDefine FCGID> 439 FcgidProcessTableFile $RTHOME/var/fcgid_shm 440 FcgidIPCDir $RTHOME/var 441 FcgidMaxRequestLen 1073741824 442 ScriptAlias $PATH $RTHOME/sbin/rt-server.fcgi/ 443 <Location $PATH> 444 Options +ExecCGI 445 AddHandler fcgid-script fcgi 446 </Location> 447</IfDefine> 448</IfDefine> 449 450 451<IfDefine RT3> 452########## 3.8 mod_perl 453<IfDefine PERL> 454 PerlSetEnv RT_SITE_CONFIG $RTHOME/etc/RT_SiteConfig.pm 455 PerlRequire "$RTHOME/bin/webmux.pl" 456 <Location $PATH/NoAuth/images> 457 SetHandler default 458 </Location> 459 <Location $PATH> 460 SetHandler perl-script 461 PerlResponseHandler RT::Mason 462 </Location> 463</IfDefine> 464 465########## 3.8 mod_fastcgi 466<IfDefine FASTCGI> 467 FastCgiIpcDir $RTHOME/var 468 FastCgiServer $RTHOME/bin/mason_handler.fcgi -processes $PROCESSES -idle-timeout 300 469 ScriptAlias $PATH $RTHOME/bin/mason_handler.fcgi/ 470 <Location $PATH> 471 Options +ExecCGI 472 AddHandler fastcgi-script fcgi 473 </Location> 474</IfDefine> 475 476########## 3.8 mod_fcgid 477<IfDefine FCGID> 478 FcgidProcessTableFile $RTHOME/var/fcgid_shm 479 FcgidIPCDir $RTHOME/var 480 FcgidMaxRequestLen 1073741824 481 ScriptAlias $PATH $RTHOME/bin/mason_handler.fcgi/ 482 <Location $PATH> 483 Options +ExecCGI 484 AddHandler fcgid-script fcgi 485 </Location> 486</IfDefine> 487</IfDefine> 488 489<IfDefine SSL> 490 SSLRandomSeed startup builtin 491 SSLRandomSeed startup file:/dev/urandom 512 492 SSLRandomSeed connect builtin 493 SSLRandomSeed connect file:/dev/urandom 512 494 SSLSessionCache shmcb:$RTHOME/var/ssl_scache(512000) 495 <IfVersion < 2.4> 496 SSLMutex file:$RTHOME/var/ssl_mutex 497 </IfVersion> 498 <VirtualHost *:$SSL> 499 SSLEngine on 500 SSLCertificateFile $TOOLS/localhost.crt 501 SSLCertificateKeyFile $TOOLS/localhost.key 502 </VirtualHost> 503</IfDefine> 504