From 9677df40abb14de2d6b1e1d9f9c5351cd36c6d4c Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Fri, 6 Apr 2018 19:15:20 +0200 Subject: [PATCH] letsencrypt install + ssl nginx conf vhost --- assets/defaultssl.nginxconf | 54 ++++++++++++ assets/drupal-ssl.nginxconf | 137 +++++++++++++++++++++++++++++ assets/drupal.nginxconf | 6 +- assets/nginx-phpmyadmin.conf | 31 ------- assets/simple-phpfpm-ssl.nginxconf | 62 +++++++++++++ assets/simple-phpfpm.nginxconf | 54 ++++++------ install-debian-server.sh | 78 +++++++++++----- 7 files changed, 341 insertions(+), 81 deletions(-) create mode 100644 assets/defaultssl.nginxconf create mode 100644 assets/drupal-ssl.nginxconf delete mode 100644 assets/nginx-phpmyadmin.conf create mode 100644 assets/simple-phpfpm-ssl.nginxconf diff --git a/assets/defaultssl.nginxconf b/assets/defaultssl.nginxconf new file mode 100644 index 0000000..4c8981c --- /dev/null +++ b/assets/defaultssl.nginxconf @@ -0,0 +1,54 @@ +# https://www.howtoforge.com/tutorial/install-letsencrypt-and-secure-nginx-in-debian-9/ +# NOT USED +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + + server_name www.yourdomain.com yourdomain.com; + #server_name _; + + root /var/www/html; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + #SSL Certificates + ssl_certificate "/etc/letsencrypt/live/www.yourdomain.com/cert.pem"; + ssl_certificate_key "/etc/letsencrypt/live/www. yourdomain.com/privkey.pem"; + ssl_dhparam /etc/nginx/dhparam.pem; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + #ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + add_header Strict-Transport-Security "max-age=31536000; + #includeSubDomains" always; + + location / { + index index.php index.html index.htm; + try_files $uri $uri/ /index.php?$args $uri/ =404; + } + + set $cache_uri $request_uri; + + location ~ /.well-known { + allow all; + } + + # pass PHP scripts to FastCGI server + location ~ \.php$ { + fastcgi_pass unix:/run/php/php7.0-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + location ~ /\.ht { + deny all; + } + +} diff --git a/assets/drupal-ssl.nginxconf b/assets/drupal-ssl.nginxconf new file mode 100644 index 0000000..1fcaed7 --- /dev/null +++ b/assets/drupal-ssl.nginxconf @@ -0,0 +1,137 @@ +# https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +# https://www.howtoforge.com/tutorial/install-letsencrypt-and-secure-nginx-in-debian-9/ +server { + listen 80; + server_name DOMAIN.LTD; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name DOMAIN.LTD; + + root /var/www/DOMAIN.LTD/public_html; + + #SSL Certificates + ssl_certificate "/etc/letsencrypt/live/DOMAIN.LTD/cert.pem"; + ssl_certificate_key "/etc/letsencrypt/live/DOMAIN.LTD/privkey.pem"; + ssl_dhparam /etc/nginx/dhparam.pem; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + #ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + add_header Strict-Transport-Security "max-age=31536000; + #includeSubDomains" always; + + charset utf-8; + + location = /favicon.ico { + access_log off; + log_not_found off; + } + + location = /robots.txt { + allow all; + access_log off; + log_not_found off; + } + + location ~ \..*/.*\.php$ { + return 403; + } + + location ~ ^/sites/.*/private/ { + return 403; + } + + # Block access to scripts in site files directory + location ~ ^/sites/[^/]+/files/.*\.php$ { + deny all; + } + + # Allow "Well-Known URIs" as per RFC 5785 + location ~* ^/.well-known/ { + allow all; + } + + # Block access to "hidden" files and directories whose names begin with a + # period. This includes directories used by version control systems such + # as Subversion or Git to store control files. + location ~ (^|/)\. { + return 403; + } + + location / { + # try_files $uri @rewrite; # For Drupal <= 6 + try_files $uri /index.php?$query_string; # For Drupal >= 7 + } + + location @rewrite { + rewrite ^/(.*)$ /index.php?q=$1; + } + + # Don't allow direct access to PHP files in the vendor directory. + location ~ /vendor/.*\.php$ { + deny all; + return 404; + } + + location ~ /\.ht { + deny all; + } + + access_log on; + error_log /var/www/DOMAIN.LTD/log/error.log; + + sendfile off; + + client_max_body_size 100m; + + # In Drupal 8, we must also match new paths where the '.php' appears in + # the middle, such as update.php/selection. The rule we use is strict, + # and only allows this pattern with the update.php front controller. + # This allows legacy path aliases in the form of + # blog/index.php/legacy-path to continue to route to Drupal nodes. If + # you do not have any paths like that, then you might prefer to use a + # laxer rule, such as: + # location ~ \.php(/|$) { + # The laxer rule will continue to work if Drupal uses this new URL + # pattern with front controllers other than update.php in a future + # release. + location ~ '\.php$|^/update.php' { + # fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + include fastcgi_params; + # Block httpoxy attacks. See https://httpoxy.org/. + fastcgi_param HTTP_PROXY ""; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + fastcgi_intercept_errors on; + # fastcgi_buffer_size 16k; + # fastcgi_buffers 4 16k; + fastcgi_pass unix:/run/php/php7.0-fpm.sock; + } + # Fighting with Styles? This little gem is amazing. + # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 + location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7 + try_files $uri @rewrite; + } + + # Handle private files through Drupal. Private file's path can come + # with a language prefix. + location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7 + try_files $uri /index.php?$query_string; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + try_files $uri @rewrite; + expires max; + log_not_found off; + } +} diff --git a/assets/drupal.nginxconf b/assets/drupal.nginxconf index bfeead8..72d182d 100644 --- a/assets/drupal.nginxconf +++ b/assets/drupal.nginxconf @@ -1,8 +1,8 @@ # https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ server { listen 80; - server_name yourdomain.ltd; - root /var/www/yourdomain.ltd/public_html; + server_name DOMAIN.LTD; + root /var/www/DOMAIN.LTD/public_html; charset utf-8; @@ -62,7 +62,7 @@ server { } access_log on; - error_log /var/www/yourdomain.ltd/log/error.log; + error_log /var/www/DOMAIN.LTD/log/error.log; sendfile off; diff --git a/assets/nginx-phpmyadmin.conf b/assets/nginx-phpmyadmin.conf deleted file mode 100644 index a8495c3..0000000 --- a/assets/nginx-phpmyadmin.conf +++ /dev/null @@ -1,31 +0,0 @@ -server { - listen 80; - location /phpmyadmin { - # server_name phpmyadmin.idroot.net; - root /usr/share/phpmyadmin; - - index index.php; - - ## Images and static content is treated different - location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ { - access_log off; - expires max; - } - - location ~ /\.ht { - deny all; - } - - location ~ /(libraries|setup/frames|setup/libs) { - deny all; - return 404; - } - - location ~ \.php$ { - fastcgi_pass unix:/run/php/php7.0-fpm.sock; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - } - } -} diff --git a/assets/simple-phpfpm-ssl.nginxconf b/assets/simple-phpfpm-ssl.nginxconf new file mode 100644 index 0000000..c2b4094 --- /dev/null +++ b/assets/simple-phpfpm-ssl.nginxconf @@ -0,0 +1,62 @@ +# https://www.howtoforge.com/tutorial/install-letsencrypt-and-secure-nginx-in-debian-9/ + +server { + listen 80; + server_name DOMAIN.LTD; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name DOMAIN.LTD; + + root /var/www/DOMAIN.LTD/public_html; + index index.html index.php; + + charset utf-8; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log on; + error_log /var/www/DOMAIN.LTD/log/error.log; + + sendfile off; + + client_max_body_size 100m; + + #SSL Certificates + ssl_certificate "/etc/letsencrypt/live/DOMAIN.LTD/cert.pem"; + ssl_certificate_key "/etc/letsencrypt/live/DOMAIN.LTD/privkey.pem"; + ssl_dhparam /etc/nginx/dhparam.pem; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + #ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + add_header Strict-Transport-Security "max-age=31536000; + #includeSubDomains" always; + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/run/php/php7.0-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + } + + location ~ /\.ht { + deny all; + } +} diff --git a/assets/simple-phpfpm.nginxconf b/assets/simple-phpfpm.nginxconf index ec10d9b..4cd2d71 100644 --- a/assets/simple-phpfpm.nginxconf +++ b/assets/simple-phpfpm.nginxconf @@ -1,38 +1,38 @@ server { - listen 80; - server_name yourdomain.ltd; + listen 80; + server_name DOMAIN.LTD; - root /var/www/yourdomain.ltd/public_html; - index index.html index.php; + root /var/www/DOMAIN.LTD/public_html; + index index.html index.php; - charset utf-8; + charset utf-8; - location / { - try_files $uri $uri/ /index.php?$query_string; - } + location / { + try_files $uri $uri/ /index.php?$query_string; + } - location = /favicon.ico { access_log off; log_not_found off; } - location = /robots.txt { access_log off; log_not_found off; } + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } - access_log on; - error_log /var/www/yourdomain.ltd/log/error.log; + access_log on; + error_log /var/www/DOMAIN.LTD/log/error.log; - sendfile off; + sendfile off; - client_max_body_size 100m; + client_max_body_size 100m; - location ~ \.php$ { - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:/run/php/php7.0-fpm.sock; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_intercept_errors off; - fastcgi_buffer_size 16k; - fastcgi_buffers 4 16k; - } + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/run/php/php7.0-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + } - location ~ /\.ht { - deny all; - } + location ~ /\.ht { + deny all; + } } diff --git a/install-debian-server.sh b/install-debian-server.sh index 1b1579c..c2d68ff 100755 --- a/install-debian-server.sh +++ b/install-debian-server.sh @@ -433,44 +433,82 @@ if [ "$lemp" = "y" ]; then done if [ "$vh" = "y" ]; then - while [ "$_host_name" = "" ] + while [ "$_domain" = "" ] do - read -p "enter a hostname ? " _host_name - if [ "$_host_name" != "" ]; then - read -p "is hostname $_host_name correcte [y|n] " validated + read -p "enter a hostname ? " _domain + if [ "$_domain" != "" ]; then + read -p "is hostname $_domain correcte [y|n] " validated if [ "$validated" = "y" ]; then break else - _host_name="" + _domain="" fi fi done - # TODO ask for simple php conf or drupal conf + # ask for simple php conf or drupal conf + while [ "$_drupal" != "yes" ] && [ "$_drupal" != "no" ] + do + echo -n "Is your site is a drupal one? [yes|no] " + read _drupal + done + # ask for let's encrypt + while [ "$_letsencrypt" != "yes" ] && [ "$_letsencrypt" != "no" ] + do + echo "Let's encrypt" + echo "Let's encrypt needs a public registered domain name with proper DNS records ( A records or CNAME records for subdomains pointing to your server)." + echo -n "Should we install let's encrypt certificate with $_domain? [yes|no] " + read _letsencrypt + done - cp "$_cwd"/assets/simple-phpfpm.nginxconf /etc/nginx/sites-available/"$_host_name".conf - sed -ir "s/yourdomain\.ltd/$_host_name/g" /etc/nginx/sites-available/"$_host_name".conf + # lets'encrypt + # https://certbot.eff.org/lets-encrypt/debianstretch-nginx + if [ "$_letsencrypt" = "yes" ]; then + apt-get install certbot + certbot certonly --cert-name "$_domain" --standalone –d "$_domain" + openssl dhparam –out /etc/nginx/dhparam.pem 2048 + # TODO renewing + touch /var/spool/crontab/root + crontab -l > mycron + echo "0 3 * * * certbot renew --pre-hook 'systemctl stop nginx' --post-hook 'systemctl start nginx' --cert-name $_domain" >> mycron + crontab mycron + rm mycron + fi - mkdir -p /var/www/"$_host_name"/public_html - mkdir /var/www/"$_host_name"/logs + if [ "$_drupal" = "yes" ]; then + if [ "$_letsencrypt" = "yes" ]; then + _conffile = "drupal-ssl.nginxconf" + else + _conffile = "drupal.nginxconf" + fi + else + if [ "$_letsencrypt" = "yes" ]; then + _conffile = "simple-phpfpm-ssl.nginxconf" + else + _conffile = "simple-phpfpm.nginxconf" + fi + fi + + cp "$_cwd"/assets/"$_conffile" /etc/nginx/sites-available/"$_domain".conf + sed -ir "s/DOMAIN\.LTD/$_domain/g" /etc/nginx/sites-available/"$_domain".conf + + mkdir -p /var/www/"$_domain"/public_html + mkdir /var/www/"$_domain"/logs #set proper right to user will handle the app - chown -R root:admin /var/www/"$_host_name"/ - chmod -R g+w /var/www/"$_host_name"/ - chmod -R g+r /var/www/"$_host_name"/ + chown -R root:admin /var/www/"$_domain"/ + chmod -R g+w /var/www/"$_domain"/ + chmod -R g+r /var/www/"$_domain"/ # create a shortcut to the site mkdir /home/"$user"/www/ chown "$user":admin /home/"$user"/www/ - ln -s /var/www/"$_host_name" /home/"$user"/www/"$_host_name" + ln -s /var/www/"$_domain" /home/"$user"/www/"$_domain" # activate the vhost - ln -s /etc/nginx/sites-available/"$_host_name".conf /etc/nginx/sites-enabled/"$_host_name".conf - - # TODO : lets'encrypt - # https://certbot.eff.org/lets-encrypt/debianstretch-nginx + ln -s /etc/nginx/sites-available/"$_domain".conf /etc/nginx/sites-enabled/"$_domain".conf # restart nginx systemctl restart nginx - echo "\033[92;1mvhost $_host_name configured\033[Om" + echo "\033[92;1mvhost $_domain configured\033[Om" else echo "Vhost installation aborted" fi @@ -569,7 +607,7 @@ if [ "$lemp" = "y" ]; then # # Configure AWStats # temp=`grep -i sitedomain /etc/awstats/awstats.conf.local | wc -l` # if [ $temp -lt 1 ]; then - # echo SiteDomain="$_host_name" >> /etc/awstats/awstats.conf.local + # echo SiteDomain="$_domain" >> /etc/awstats/awstats.conf.local # fi # # Disable Awstats from executing every 10 minutes. Put a hash in front of any line. # sed -i 's/^[^#]/#&/' /etc/cron.d/awstats