Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / rt / devel / tools / rt-apache
1 #!/usr/bin/env perl
2
3 # BEGIN BPS TAGGED BLOCK {{{
4 #
5 # COPYRIGHT:
6 #
7 # This software is Copyright (c) 1996-2015 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 }}}
50 use strict;
51 use warnings;
52
53 use Getopt::Long;
54 use FindBin;
55 use Pod::Usage;
56 use File::Spec::Functions qw(rel2abs);
57
58 my %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
68 GetOptions(  \%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 );
86 pod2usage( {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
93 my $mod;
94 if ($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
108 die "$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
112 if (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
119 my $RTCONF;
120 $opt{port} ||= parseconf( "WebPort" );
121 unless ($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
133 if (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
145 my $path = parseconf( "WebPath" ) || "";
146
147 my $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
158 my $conf = "$opt{root}/var/apache.conf";
159 open(CONF, ">", $conf)
160     or die "Can't write $conf: $!";
161 print CONF $template;
162 close CONF;
163
164 my @opts = ("-f", $conf, "-D" . uc($mod) );
165 push @opts, "-DSSL" if $opt{ssl};
166 push @opts, "-DRT3" if $opt{rt3};
167 push @opts, "-DSINGLE" if $opt{single};
168
169 # Wait for a previous run to terminate
170 if ( open( PIDFILE, "<", "$opt{root}/var/apache2.pid") ) {
171     my $pid = <PIDFILE>;
172     chomp $pid;
173     close PIDFILE;
174     if ($pid and kill 0, $pid) {
175         warn "Waiting for previous run (pid $pid) to finish...\n";
176         sleep 1 while kill 0, $pid;
177     }
178 }
179
180 # Clean out the log in preparation
181 my $log = "$opt{root}/var/log/apache-error.log";
182 unlink($log);
183
184 # Start 'er up
185 warn "Starting apache server on http://localhost:$opt{port}$path/"
186     . ($opt{ssl} ? " and https://localhost:$opt{ssl}$path/" : "") . "\n";
187 !system("apache2", @opts, "-k", "start")
188     or die "Can't exec apache2: $@";
189 # Ignore the return value, as we expect it to be ^C'd
190 system("tail", "-f", $log);
191 warn "Shutting down apache...\n";
192 !system("apache2", @opts, "-k", "stop")
193     or die "Can't exec apache2: $@";
194
195
196 sub parseconf {
197     my ($optname) = @_;
198     # We're going to be evil, and try to parse the config
199     unless (defined $RTCONF) {
200         unless ( open(CONF, "<", "$opt{root}/etc/RT_SiteConfig.pm") ) {
201             warn "Can't open $opt{root}/etc/RT_SiteConfig.pm: $!\n";
202             $RTCONF = "";
203             return;
204         }
205         $RTCONF = join("", <CONF>);
206         close CONF;
207     }
208
209     return unless $RTCONF =~ /^\s*Set\(\s*\$$optname\s*(?:,|=>)\s*['"]?(.*?)['"]?\s*\)/m;
210     return $1;
211 }
212
213 =head1 NAME
214
215 rt-apache - Wrapper to start Apache running RT
216
217 =head1 DESCRIPTION
218
219 This script exists to make it easier to run RT under Apache for testing.
220 It is not intended as a way to deploy RT, or to provide example Apache
221 configuration for RT.  For instructions on how to deploy RT with Apache,
222 please read the provided F<docs/web_deployment.pod> file.
223
224 Running this script will start F<apache2> with a custom-built
225 configuration file, built based on command-line options and the contents
226 of your F<RT_SiteConfig.pm>.  It will work with either RT 3.8.x or RT
227 4.0.x.  As it is primarily for simple testing, it runs Apache as the
228 current user.
229
230 =head1 OPTIONS
231
232 C<rt-apache> will parse your F<RT_SiteConfig.pm> for its C<WebPath> and
233 C<WebPort> configuration, and adjust its defaults accordingly.
234
235 =over
236
237 =item --root B<path>
238
239 The path to the RT install to serve.  This defaults to the C<RTHOME>
240 environment variable, or C</opt/rt4>.
241
242 =item --fastcgi, --fcgid, --perl
243
244 Determines the Apache module which is used.  By default, the first one
245 of that list which exists will be used.  See also L</--modules>.
246
247 =item --port B<number>, -p
248
249 Choses the port to listen on.  By default, this is parsed from the
250 F<RT_SiteConfig.pm>, and falling back to 8888.
251
252 =item --ssl [B<number>]
253
254 Also listens on the provided port with HTTPS, using a self-signed
255 certificate for C<localhost>.  If the port number is not specified,
256 defaults to port 4430.
257
258 =item --auth [F</path/to/htpasswd>], -A
259
260 Turns on HTTP Basic Authentication; this is done automatically if
261 C<$WebRemoteUserAuth> is set in the F<RT_SiteConfig.pm>.  The provided
262 path should be to a F<htpasswd> file; if not given, defaults to a file
263 containing only user C<root> with password C<password>.
264
265 =item --single, -X
266
267 Run only one process or thread, for ease of debugging.
268
269 =item --rt3, -3
270
271 Declares that the RT install in question is RT 3.8.x.  C<rt-apache> can
272 usually detect this for you, however.
273
274 =item --modules B<path>
275
276 The path to the Apache2 modules directory, which is expected to contain
277 at least one of F<mod_fcgid.so>, F<mod_fastcgi.so>, or F<mod_perl.so>.
278 Defaults to F</usr/lib/apache2/modules>.
279
280 =back
281
282 =cut
283
284 __DATA__
285 <IfDefine SINGLE>
286     <IfModule mpm_prefork_module>
287         StartServers          1
288         MinSpareServers       1
289         MaxSpareServers       1
290         MaxClients            1
291         MaxRequestsPerChild   0
292     </IfModule>
293
294     <IfModule mpm_worker_module>
295         StartServers          1
296         MinSpareThreads       1
297         MaxSpareThreads       1
298         ThreadLimit           1
299         ThreadsPerChild       1
300         MaxClients            1
301         MaxRequestsPerChild   0
302     </IfModule>
303 </IfDefine>
304
305 Listen $PORT
306 <IfDefine SSL>
307    Listen $SSL
308 </IfDefine>
309
310 ServerName localhost
311 ServerRoot $RTHOME/var
312 PidFile    $RTHOME/var/apache2.pid
313 LockFile   $RTHOME/var/apache2.lock
314 ServerAdmin root@localhost
315
316 LoadModule authz_host_module  $MODULES/mod_authz_host.so
317 LoadModule env_module         $MODULES/mod_env.so
318 LoadModule alias_module       $MODULES/mod_alias.so
319 LoadModule mime_module        $MODULES/mod_mime.so
320 TypesConfig $TOOLS/mime.types
321
322 <IfDefine PERL>
323     LoadModule perl_module    $MODULES/mod_perl.so
324 </IfDefine>
325 <IfDefine FASTCGI>
326     LoadModule fastcgi_module $MODULES/mod_fastcgi.so
327 </IfDefine>
328 <IfDefine FCGID>
329     LoadModule fcgid_module   $MODULES/mod_fcgid.so
330 </IfDefine>
331 <IfDefine SSL>
332     LoadModule ssl_module     $MODULES/mod_ssl.so
333 </IfDefine>
334
335 <IfModule !log_config_module>
336     LoadModule log_config_module $MODULES/mod_log_config.so
337 </IfModule>
338 ErrorLog    "$RTHOME/var/log/apache-error.log"
339 TransferLog "$RTHOME/var/log/apache-access.log"
340 LogLevel notice
341
342 <Directory />
343     Options FollowSymLinks
344     AllowOverride None
345     Order deny,allow
346     Deny from all
347 </Directory>
348
349 AddDefaultCharset UTF-8
350
351 DocumentRoot $RTHOME/share/html
352 <Directory $RTHOME/share/html>
353     Order allow,deny
354     Allow from all
355 </Directory>
356
357 Alias $PATH/NoAuth/images/ $RTHOME/share/html/NoAuth/images/
358 <Directory $RTHOME/share/html/NoAuth/images>
359     Order allow,deny
360     Allow from all
361 </Directory>
362
363 <IfDefine !RT3>
364 ########## 4.0 mod_perl
365 <IfDefine PERL>
366     PerlSetEnv RT_SITE_CONFIG $RTHOME/etc/RT_SiteConfig.pm
367     <Location $PATH>
368         Order allow,deny
369         Allow from all
370         SetHandler modperl
371         PerlResponseHandler Plack::Handler::Apache2
372         PerlSetVar psgi_app $RTHOME/sbin/rt-server
373     </Location>
374     <Perl>
375         use Plack::Handler::Apache2;
376         Plack::Handler::Apache2->preload("$RTHOME/sbin/rt-server");
377     </Perl>
378 </IfDefine>
379
380 ########## 4.0 mod_fastcgi
381 <IfDefine FASTCGI>
382     FastCgiIpcDir $RTHOME/var
383     FastCgiServer $RTHOME/sbin/rt-server.fcgi -processes $PROCESSES -idle-timeout 300
384     ScriptAlias $PATH $RTHOME/sbin/rt-server.fcgi/
385     <Location $PATH>
386         Order allow,deny
387         Allow from all
388         Options +ExecCGI
389         AddHandler fastcgi-script fcgi
390     </Location>
391 </IfDefine>
392
393 ########## 4.0 mod_fcgid
394 <IfDefine FCGID>
395     FcgidProcessTableFile $RTHOME/var/fcgid_shm
396     FcgidIPCDir $RTHOME/var
397     FcgidMaxRequestLen 1073741824
398     ScriptAlias $PATH $RTHOME/sbin/rt-server.fcgi/
399     <Location $PATH>
400         Order allow,deny
401         Allow from all
402         Options +ExecCGI
403         AddHandler fcgid-script fcgi
404     </Location>
405 </IfDefine>
406 </IfDefine>
407
408
409 <IfDefine RT3>
410 ########## 3.8 mod_perl
411 <IfDefine PERL>
412     PerlSetEnv RT_SITE_CONFIG $RTHOME/etc/RT_SiteConfig.pm
413     PerlRequire "$RTHOME/bin/webmux.pl"
414     <Location $PATH/NoAuth/images>
415         SetHandler default
416     </Location>
417     <Location $PATH>
418         SetHandler perl-script
419         PerlResponseHandler RT::Mason
420     </Location>
421 </IfDefine>
422
423 ########## 3.8 mod_fastcgi
424 <IfDefine FASTCGI>
425     FastCgiIpcDir $RTHOME/var
426     FastCgiServer $RTHOME/bin/mason_handler.fcgi -processes $PROCESSES -idle-timeout 300
427     ScriptAlias $PATH $RTHOME/bin/mason_handler.fcgi/
428     <Location $PATH>
429         Order allow,deny
430         Allow from all
431         Options +ExecCGI
432         AddHandler fastcgi-script fcgi
433     </Location>
434 </IfDefine>
435
436 ########## 3.8 mod_fcgid
437 <IfDefine FCGID>
438     FcgidProcessTableFile $RTHOME/var/fcgid_shm
439     FcgidIPCDir $RTHOME/var
440     FcgidMaxRequestLen 1073741824
441     ScriptAlias $PATH $RTHOME/bin/mason_handler.fcgi/
442     <Location $PATH>
443         Order allow,deny
444         Allow from all
445         Options +ExecCGI
446         AddHandler fcgid-script fcgi
447     </Location>
448 </IfDefine>
449 </IfDefine>
450
451 <IfDefine SSL>
452     SSLRandomSeed startup builtin
453     SSLRandomSeed startup file:/dev/urandom 512
454     SSLRandomSeed connect builtin
455     SSLRandomSeed connect file:/dev/urandom 512
456     SSLSessionCache shmcb:$RTHOME/var/ssl_scache(512000)
457     SSLMutex file:$RTHOME/var/ssl_mutex
458     <VirtualHost *:$SSL>
459         SSLEngine on
460         SSLCertificateFile    $TOOLS/localhost.crt
461         SSLCertificateKeyFile $TOOLS/localhost.key
462     </VirtualHost>
463 </IfDefine>