|
@@ -0,0 +1,221 @@
|
|
|
|
+#!/usr/bin/perl
|
|
|
|
+use strict;
|
|
|
|
+use warnings;
|
|
|
|
+use Config::General;
|
|
|
|
+use Data::Dumper;
|
|
|
|
+use Text::Xslate qw(mark_raw);
|
|
|
|
+use File::Slurp;
|
|
|
|
+use File::Copy;
|
|
|
|
+open STDERR, '>', "/dev/null";
|
|
|
|
+
|
|
|
|
+my $LCWM = '/etc/nginx/lcwm2';
|
|
|
|
+my $A2CFG = '/etc/httpd/conf/httpd.conf' ;
|
|
|
|
+my $NGCFG = '/etc/nginx/nginx.conf' ;
|
|
|
|
+my $NGCFGen = "$NGCFG.gen" ;
|
|
|
|
+my $NGCFGbak = "$NGCFG." . time() ;
|
|
|
|
+my $A2PORT = 81 ;
|
|
|
|
+my $A2PORTS = 8443 ;
|
|
|
|
+my $NGPORT = 80 ;
|
|
|
|
+my $NGPORTS = 443 ;
|
|
|
|
+my $NGCFGBASE = "$LCWM/nginx.base" ;
|
|
|
|
+my $NGCFGVHOSTSTAT = "$LCWM/vhost_static.conf" ;
|
|
|
|
+my $NGCFG_CUSTOM_DIR = "$LCWM/custom";
|
|
|
|
+my $A2CLEAN = "$LCWM/ap2_clean.conf" ;
|
|
|
|
+my $DEFLISTEN = " default sndbuf=98304 backlog=2048 deferred" ;
|
|
|
|
+
|
|
|
|
+my $template_def_ips = qq{
|
|
|
|
+# aka null.tld + $DEFLISTEN
|
|
|
|
+server {
|
|
|
|
+ : for \$ipv4 -> \$ip {
|
|
|
|
+ listen <: \$ip :>:$NGPORT $DEFLISTEN;
|
|
|
|
+ : }
|
|
|
|
+ : for \$ipv6 -> \$ip {
|
|
|
|
+ listen <: \$ip :>:$NGPORT $DEFLISTEN;
|
|
|
|
+ : }
|
|
|
|
+ access_log off;
|
|
|
|
+ error_log /dev/null;
|
|
|
|
+ server_name "";
|
|
|
|
+ return 444;
|
|
|
|
+}
|
|
|
|
+};
|
|
|
|
+my $template_ng_vhost = q{
|
|
|
|
+#---vhost for domain <: $server_name :> on IP <: $listen :> <: $ssl :> ----
|
|
|
|
+server {
|
|
|
|
+ : for $ips.ipv4 -> $ip {
|
|
|
|
+ listen <: $ip :>:<: $ngport :> <: $ssl :>;
|
|
|
|
+ : }
|
|
|
|
+ : for $ips.ipv6 -> $ip {
|
|
|
|
+ listen <: $ip :>:<: $ngport :> <: $ssl :>;
|
|
|
|
+ : }
|
|
|
|
+ server_name <: $server_name :> <: $alias :> ;
|
|
|
|
+ root <: $root :> ;
|
|
|
|
+ access_log off; # /var/log/nginx/<: $server_name :>.access.log main buffer=32k;
|
|
|
|
+ error_log /var/log/nginx/<: $server_name :>.error.log warn;
|
|
|
|
+ : if $include_slash == "" {
|
|
|
|
+ location @apache {
|
|
|
|
+ proxy_pass http://<: $main_ip :>:<: $a2port :>;
|
|
|
|
+ proxy_redirect http://<: $server_name :>:<: $a2port :> http://<: $server_name :>;
|
|
|
|
+ proxy_redirect http://www.<: $server_name :>:<: $a2port :> http://www.<: $server_name :>;
|
|
|
|
+ proxy_redirect http://webmail.<: $server_name :>:<: $a2port :> http://webmail.<: $server_name :>;
|
|
|
|
+ proxy_redirect http://admin.<: $server_name :>:<: $a2port :> http://admin.<: $server_name :>;
|
|
|
|
+ }
|
|
|
|
+ location / {
|
|
|
|
+ try_files maintenance.html @apache;
|
|
|
|
+ }
|
|
|
|
+ : } else {
|
|
|
|
+ <: $include_slash :>
|
|
|
|
+ : }
|
|
|
|
+ <: $include_static :>
|
|
|
|
+ : if $ssl != "" {
|
|
|
|
+ ssl_certificate <: $ssl_certificate :> ;
|
|
|
|
+ ssl_certificate_key <: $ssl_certificate_key :> ;
|
|
|
|
+ ssl_session_timeout 1d;
|
|
|
|
+ ssl_session_cache shared:SSL:50m;
|
|
|
|
+ ssl_session_tickets off;
|
|
|
|
+ ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
|
|
|
+ ssl_protocols TLSv1.2;
|
|
|
|
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
|
|
|
+ ssl_prefer_server_ciphers on;
|
|
|
|
+ #ssl_stapling on;
|
|
|
|
+ #ssl_stapling_verify on;
|
|
|
|
+ resolver 8.8.8.8;
|
|
|
|
+ : }
|
|
|
|
+}
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+sub update_pem {
|
|
|
|
+# Bash analog:
|
|
|
|
+# cat $SSLSERT > $SSLSERT".pem"
|
|
|
|
+# cat $SSLCA >> $SSLSERT".pem"
|
|
|
|
+#
|
|
|
|
+ my ($SSLSERT, $SSLCA) = @_ ;
|
|
|
|
+ my $OUT = $SSLSERT . ".pem";
|
|
|
|
+ write_file( $OUT, {append => 0 }, read_file($SSLSERT) ) ;
|
|
|
|
+ write_file( $OUT, {append => 1 }, read_file($SSLCA) ) if ( $SSLCA );
|
|
|
|
+ return $OUT;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+sub uniq {
|
|
|
|
+# remove duplicates from array
|
|
|
|
+#
|
|
|
|
+ my %seen;
|
|
|
|
+ return grep { !$seen{$_}++ } @_;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+sub get_ips {
|
|
|
|
+# get array of ips from VirtualHost string, like this "IP1:http IP2:http [ipv6_1]:http [ipv6_2]:http"
|
|
|
|
+#
|
|
|
|
+ my ($text) = @_ ;
|
|
|
|
+ my %hash;
|
|
|
|
+ my @ipv6 = uniq ( $text =~ m/\[.+?\]/sg ) ;
|
|
|
|
+ my @ipv6_wo_local = grep ! /\[fe80/, @ipv6 ;
|
|
|
|
+ @ipv6_wo_local = grep ! /\[2001/, @ipv6_wo_local ;
|
|
|
|
+ my @ipv4 = uniq ( $text =~ m/[0-9.]{7,}/sg ) ;
|
|
|
|
+ $hash{ipv6} = \@ipv6_wo_local ;
|
|
|
|
+ $hash{ipv4} = \@ipv4 ;
|
|
|
|
+ return \%hash ;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+sub cook_ng_vhost {
|
|
|
|
+# convert [httpd.conf->Config::General]=>@vh_array->{$vhost} to %ng_hash=>[Text::Xslate->nginx.conf]
|
|
|
|
+#
|
|
|
|
+ my ($vh, $ip_port) = @_ ;
|
|
|
|
+ my $port = $vh->{SSLEngine} ? $NGPORTS : $NGPORT ;
|
|
|
|
+ my %hash;
|
|
|
|
+ my $server_name = $vh->{ServerName};
|
|
|
|
+ my @statics = glob "/home/*/configs/$server_name.static /etc/nginx/*/custom/$server_name.static";
|
|
|
|
+ my @slashes = glob "/home/*/configs/$server_name.slash /etc/nginx/*/custom/$server_name.slash";
|
|
|
|
+ my $include_static = "/fake_path";
|
|
|
|
+ my $include_slash = "/fake_path";
|
|
|
|
+ $include_static = $statics[0] if $statics[0] ;
|
|
|
|
+ $include_slash = $slashes[0] if $slashes[0] ;
|
|
|
|
+ #print $server_name . " " . $include_static . " " . $include_slash . "\n";
|
|
|
|
+ $hash{'alias'} = ref $vh->{ServerAlias} eq 'ARRAY' ? join(" ", @{$vh->{ServerAlias}}) : $vh->{ServerAlias} ;
|
|
|
|
+ $hash{'root'} = $vh->{DocumentRoot} ;
|
|
|
|
+ $hash{'server_name'} = $vh->{ServerName} ;
|
|
|
|
+ $hash{'main_ip'} = get_ips($ip_port)->{ipv4}[0] ;
|
|
|
|
+ $hash{'a2port'} = $A2PORT ;
|
|
|
|
+ $hash{'ips'} = get_ips($ip_port) ;
|
|
|
|
+ $hash{'ngport'} = $vh->{SSLEngine} ? $NGPORTS : $NGPORT ;
|
|
|
|
+ $hash{'ssl'} = $vh->{SSLEngine} ? "ssl" : "";
|
|
|
|
+ $hash{'ssl_certificate'} = $vh->{SSLEngine} ? update_pem( $vh->{SSLCertificateFile}, $vh->{SSLCACertificateFile} ) : "" ;
|
|
|
|
+ $hash{'ssl_certificate_key'} = $vh->{SSLCertificateKeyFile} ;
|
|
|
|
+ $hash{'include_static'} = (-f $include_static ) ? read_file( $include_static ) : "include $NGCFGVHOSTSTAT;" ;
|
|
|
|
+ $hash{'include_slash'} = (-f $include_slash ) ? read_file( $include_slash ) : "" ;
|
|
|
|
+ $hash{'include_static'} = mark_raw( $hash{'include_static'} ) ;
|
|
|
|
+ $hash{'include_slash'} = mark_raw( $hash{'include_slash'} ) ;
|
|
|
|
+ return \%hash;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+sub cook_ng_array {
|
|
|
|
+ open(my $a2cfg, '<:encoding(utf8)', $A2CFG ) or die "unable to open $A2CFG: $!\n";
|
|
|
|
+ open(my $a2clean, "+>", $A2CLEAN) or die "$0: can't create temporary file: $!\n";
|
|
|
|
+ while (<$a2cfg>) { print $a2clean "$_" if ( /^\<VirtualHost/ .. /\<\/VirtualHost\>/ ) } ;
|
|
|
|
+ close $a2cfg;
|
|
|
|
+ close $a2clean;
|
|
|
|
+
|
|
|
|
+ my %conf = Config::General->new($A2CLEAN)->getall();
|
|
|
|
+ unlink $A2CLEAN;
|
|
|
|
+ my @ng_array = ();
|
|
|
|
+ for my $ip_port (keys %{$conf{VirtualHost}}) {
|
|
|
|
+ if ( ref $conf{VirtualHost}{$ip_port} eq 'ARRAY' ) {
|
|
|
|
+ for my $vh ( @{$conf{VirtualHost}{$ip_port}} ) {
|
|
|
|
+ if (exists $vh->{ServerName} and exists $vh->{ServerAlias}) {
|
|
|
|
+ push @ng_array, cook_ng_vhost($vh, $ip_port);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ my $vh = $conf{VirtualHost}{$ip_port} ;
|
|
|
|
+ if (exists $vh->{ServerName} and exists $vh->{ServerAlias}) {
|
|
|
|
+ push @ng_array, cook_ng_vhost( $vh, $ip_port);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return \@ng_array;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+sub render_ng {
|
|
|
|
+ my $tx = Text::Xslate->new();
|
|
|
|
+ write_file($NGCFGen, {append => 0 }, read_file( $NGCFGBASE ) );
|
|
|
|
+ #print Dumper @ng_array;
|
|
|
|
+ ## TO DO, rm durty code
|
|
|
|
+ my $get_string_with_all_ips = `grep VirtualHost $A2CFG`;
|
|
|
|
+ write_file( $NGCFGen, {append => 1 }, $tx->render_string( $template_def_ips, get_ips ( $get_string_with_all_ips ) ) );
|
|
|
|
+ ## /TO DO
|
|
|
|
+ foreach my $vhost (values cook_ng_array){
|
|
|
|
+ write_file( $NGCFGen, {append => 1 }, $tx->render_string( $template_ng_vhost, $vhost ) );
|
|
|
|
+ }
|
|
|
|
+ write_file( $NGCFGen, {append => 1 }, "\n\#close section http {\n}" ) ;
|
|
|
|
+ print "Config done ... " ;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+sub reconf_ng {
|
|
|
|
+ my @args = ("/usr/sbin/nginx", "-t", "-c", "$NGCFGen" );
|
|
|
|
+ # Debug
|
|
|
|
+ copy($NGCFGen, '/etc/nginx/test.conf');
|
|
|
|
+ # -----
|
|
|
|
+ if ( system(@args) == 0 ) {
|
|
|
|
+ print "syntax is ok ... ";
|
|
|
|
+ } else {
|
|
|
|
+ print "syntax check failed ...\n";
|
|
|
|
+ die "system @args failed: $?";
|
|
|
|
+ }
|
|
|
|
+ move($NGCFG, $NGCFGbak);
|
|
|
|
+ copy($NGCFGen, $NGCFG);
|
|
|
|
+ print "backup done ... ";
|
|
|
|
+ #@args = ("/usr/sbin/nginx", "-s", "reload" );
|
|
|
|
+ @args = ("service", "nginx", "restart" );
|
|
|
|
+ if ( system(@args) == 0 or system(@args) == 256) {
|
|
|
|
+ print "nginx reloaded. ALL OK\n";
|
|
|
|
+ } else {
|
|
|
|
+ print system(@args);
|
|
|
|
+ copy($NGCFGbak, $NGCFG);
|
|
|
|
+ print "nginx reload failed, revert config done ...\n";
|
|
|
|
+ die "system @args failed: $?";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+render_ng ;
|
|
|
|
+reconf_ng ;
|