From cd0de914bdd51286ea657859d5b5962805618d63 Mon Sep 17 00:00:00 2001 From: Manager Bot Date: Mon, 7 Nov 2022 19:35:10 +0000 Subject: [PATCH] MJB::Backend::Nginx as plugin. --- Web/lib/MJB/Web.pm | 6 ++ Web/lib/MJB/Web/Plugin/Nginx.pm | 15 ++++ Web/lib/MJB/Web/Plugin/Nginx/DomainConfig.pm | 77 ++++++++++++++++++++ Web/lib/MJB/Web/Task/InitializeBlog.pm | 60 ++++++--------- 4 files changed, 122 insertions(+), 36 deletions(-) create mode 100644 Web/lib/MJB/Web/Plugin/Nginx.pm create mode 100644 Web/lib/MJB/Web/Plugin/Nginx/DomainConfig.pm diff --git a/Web/lib/MJB/Web.pm b/Web/lib/MJB/Web.pm index 65431a3..9a85d2a 100644 --- a/Web/lib/MJB/Web.pm +++ b/Web/lib/MJB/Web.pm @@ -18,6 +18,12 @@ sub startup ($self) { # Load our custom commands. push @{$self->commands->namespaces}, 'MJB::Web::Command'; + + # Add MJB::Web::Plugin to plugin search path. + push @{$self->plugins->namespaces}, 'MJB::Web::Plugin'; + + # Load the MJB::Web::Plugin::Nginx plugin. + $self->plugins->load_plugin('Nginx'); $self->helper( db => sub { return state $db = MJB::DB->connect($config->{database}->{mjb}); diff --git a/Web/lib/MJB/Web/Plugin/Nginx.pm b/Web/lib/MJB/Web/Plugin/Nginx.pm new file mode 100644 index 0000000..6e2e412 --- /dev/null +++ b/Web/lib/MJB/Web/Plugin/Nginx.pm @@ -0,0 +1,15 @@ +package MJB::Web::Plugin::Nginx; +use Mojo::Base 'Mojolicious::Plugin', -signatures; +use MJB::Web::Plugin::Nginx::DomainConfig; + +sub register ( $self, $app, $config ) { + + $self->helper( domain_config => sub ($c, $domain, $ssl_domain) { + return MJB::Backend::Nginx::DomainConfig->new( + domain => $domain, + ssl_domain => $ssl_domain, + )->config; + }); +} + +1; diff --git a/Web/lib/MJB/Web/Plugin/Nginx/DomainConfig.pm b/Web/lib/MJB/Web/Plugin/Nginx/DomainConfig.pm new file mode 100644 index 0000000..2291ef2 --- /dev/null +++ b/Web/lib/MJB/Web/Plugin/Nginx/DomainConfig.pm @@ -0,0 +1,77 @@ +package MJB::Web::Plugin::Nginx::DomainConfig; +use Moo; +use Mojo::File; + +has domain => ( + is => 'ro', +); + +has ssl_domain => ( + is => 'ro', +); + +has template => ( + is => 'ro', + default => sub {return <<' EOF;' + server { + server_name {{ domain }}; + root /var/www/{{ domain }}/html; + index index.html; + + error_log /var/log/nginx/{{ domain }}.error.log warn; + access_log /var/log/nginx/{{ domain }}.access.log combined; + + listen 443 ssl; + ssl_certificate /etc/letsencrypt/live/{{ ssl_domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ ssl_domain }}/privkey.pem; + + ssl_session_cache shared:le_nginx_SSL:10m; + ssl_session_timeout 1440m; + ssl_session_tickets off; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers off; + + ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; + + ssl_dhparam /etc/nginx/ssl-dhparams.pem; + + } + + server { + if ($host = {{ domain }}) { + return 301 https://$host$request_uri; + } + + listen 80; + server_name {{ domain }} + return 404; + } + EOF; + } +); + +has config => ( + is => 'lazy', +); + +sub _build_config { + my ( $self ) = @_; + + my $config = $self->template; + + # Fill in variables in the template. + my ( $domain, $ssl_domain ) = ( $self->domain, $self->ssl_domain ); + + s/\{\{ domain \}\}/$domain/g, + s/\{\{ ssl_domain \}\}/$ssl_domain/g + for $config; + + # Trim the excess whitespace + $config =~ s/^ {8}//gm; + + + return $config; +} + +1; diff --git a/Web/lib/MJB/Web/Task/InitializeBlog.pm b/Web/lib/MJB/Web/Task/InitializeBlog.pm index be3ebe9..6332a47 100644 --- a/Web/lib/MJB/Web/Task/InitializeBlog.pm +++ b/Web/lib/MJB/Web/Task/InitializeBlog.pm @@ -5,27 +5,37 @@ use File::Copy::Recursive qw( dircopy ); use IPC::Run3; use MJB::Backend::Nginx::DomainConfig; -# This needs to do all of the things: -# 1 - Make nginx config -# 2 - Whatever the ansible deploy-site thing does. +#== +# This task makes the initial nginx configuration file, reloads the webservers to have +# the config take effect. Then it schedules a sync_blog task to get the initial blog up +# on the webservers. # - +# It is expected that the SSL certificates have issued before this task is run, either with +# standing wildcard SSL certs or with the task to complete and sync http challenges. If the +# SSL certs referenced in the nginx config are missing, that may cause the servers to fail to +# reload. +#== sub run ( $job, $blog_id ) { - $job->note( _mds_template => 'build_static' ); + $job->note( _mds_template => 'initialize_blog' ); my $blog = $job->app->db->blog( $blog_id ); - my $config_content = MJB::Backend::Nginx::DomainConfig->new( - domain => $blog->domain->name, - ssl_domain => ( $blog->domain->ssl ? $blog->domain->ssl : $blog->domain->name ), - )->config; - + # Create the domain config. + # When the domain uses a different domain for its ssl cert (i.e. wildcard ssl), we need to supply that. + my $domain_name = $blog->domain->name; + my $domain_ssl = $blog->domain->ssl ? $blog->domain->ssl : $blog->domain->name; + my $config_content = $job->app->domain_config( $domain_name, $domain_ssl ); + + # Put the nginx configuration file and a welcome html file into files for scp'ing to the web servers. my ( $config, $welcome ) = ( tempfile, tempfile ); $config->spurt ( $config_content ); $welcome->spurt( "Your new blog is being setup... please reload soon." ); + $job->note( is_config_created => 1 ); + # Deploy the configuration and initial index.html file to the webservers then reload the webservers for + # the config to take effect. foreach my $host ( $job->app->db->servers->all ) { my $server = 'root@' . $host->hostname; my $domain = $blog->domain->name; @@ -36,35 +46,13 @@ sub run ( $job, $blog_id ) { $job->system_command( [ 'ssh', $server, 'chown -R www-data:www-data /var/www/' . $domain ] ); $job->system_command( [ 'ssh', $server, 'systemctl reload nginx' ] ); } - - # $job->app->nginx->provision_website( $blog->domain->name ); - $job->app->sync_blog( $blog ); - - $job->note( is_clone_complete => 1 ); + $job->note( is_config_deployed => 1 ); - $job->note( is_deploy_complete => 1 ); + # Deploy the initial blog. + $job->app->sync_blog( $blog ); + $job->finish( ); - } - -# my $config = MJB::Backend::Nginx::DomainConfig->new( -# domain => $domain, -# ssl_domain => $ssl_domain, -# )->config; -# -# my $config_file = tempfile; -# $config_file->spurt( $config ); -# my $welcome_file = tempfile; -# $welcome_file->spurt( "Your new blog is being setup... please reload soon." ); -# -# foreach my $server ( @{$self->servers} ) { -# $self->system_command( [ 'scp', $config_file->to_string, $server . ":/etc/nginx/sites-enabled/" . $domain ] ); -# $self->system_command( [ 'ssh', $server, 'mkdir -p /var/www/' . $domain . '/html' ] ); -# $self->system_command( [ 'scp', $welcome_file->to_string, $server . "/var/www/" . $domain . "/html/index.html" ] ); -# $self->system_command( [ 'ssh', $server, 'chown -R www-data:www-data /var/www/' . $domain ] ); -# $self->system_command( [ 'ssh', $server, 'systemctl reload nginx' ] ); -# } - 1;