Last active
December 23, 2018 02:41
-
-
Save dkrusky/32044293470e799f7dc59d8e96dbba4e to your computer and use it in GitHub Desktop.
Configure fresh Debian 9 on Linode for hosted site with SSL, firewall, mysql, apache2, and php7.2-fpm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# set the dyndns name you want to allow access from | |
dyndns="testing.noip.me" | |
# set the domain you will be using | |
domain="testing.com" | |
# set the email address for letsencrypt | |
email="[email protected]" | |
# add repos and update | |
apt update -q -y && apt upgrade -q -y | |
apt install apt-transport-https lsb-release ca-certificates -q -y | |
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg | |
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list | |
echo "deb http://ftp.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/backports.list | |
echo -e "deb http://repo.mysql.com/apt/debian/ stretch mysql-5.7\ndeb-src http://repo.mysql.com/apt/debian/ stretch mysql-5.7" > /etc/apt/sources.list.d/mysql.list | |
wget -O /tmp/RPM-GPG-KEY-mysql https://repo.mysql.com/RPM-GPG-KEY-mysql | |
apt-key add /tmp/RPM-GPG-KEY-mysql | |
apt update -q -y | |
# fix vim mouse and syntax | |
echo "set mouse= | |
syntax on" > ~/.vimrc | |
echo "export LS_OPTIONS='--color=auto' | |
eval \"\`dircolors\`\" | |
alias ls='ls \$LS_OPTIONS' | |
alias ll='ls \$LS_OPTIONS -l' | |
alias l='ls \$LS_OPTIONS -lA' | |
alias rm='rm -i' | |
alias cp='cp -i' | |
alias mv='mv -i' | |
" > ~/.bashrc | |
# disable interactive so mysql has no root password | |
export DEBIAN_FRONTEND=noninteractive | |
# install core server stuff | |
apt install git lrzsz php7.2-cgi php7.2-cli php7.2-common php7.2-curl php7.2-fpm php7.2-gd php7.2-imap php7.2-json php7.2-mbstring php7.2-mysql php7.2-opcache php7.2-readline php7.2-soap php7.2-xml php7.2-xmlrpc php7.2-zip apache2 apache2-bin apache2-data apache2-suexec-custom apache2-utils libapache2-mod-security2 libapache2-mod-xsendfile sendmail mysql-server net-tools ipset libwww-perl libio-socket-ssl-perl libnet-ssleay-perl libgd-graph-perl unzip -q -y | |
# enable headers and ssl support in apache | |
a2enmod headers ssl xsendfile proxy_fcgi | |
a2enconf php7.2-fpm | |
service apache2 stop | |
# disable default site | |
a2dissite 000-default.conf | |
# install nodejs | |
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash | |
#export NVM_DIR="${XDG_CONFIG_HOME/:-$HOME/.}nvm" | |
#[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" | |
#nvm install node 10 | |
# install letsencrypt certbot | |
apt-get install python-certbot-apache -t stretch-backports -q -y | |
# configure default domain | |
echo " | |
<VirtualHost *:80> | |
ServerName $domain | |
ServerAlias www.$domain | |
ServerAdmin info@$domain | |
DocumentRoot /var/www/html | |
ErrorLog \${APACHE_LOG_DIR}/$domain-error.log | |
CustomLog \${APACHE_LOG_DIR}/$domain-access.log combined | |
</VirtualHost>" > /etc/apache2/sites-available/$domain.conf | |
a2ensite $domain.conf | |
service apache2 start | |
# install letsencrypt ssl | |
certbot --apache -d $domain -d www.$domain --email $email | |
# get ssl key pin | |
HPKP=`openssl x509 -in /etc/letsencrypt/live/"$domain"/cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64` | |
echo " | |
<IfModule mod_ssl.c> | |
<IfModule mod_headers.c> | |
Header Always set Strict-Transport-Security \"max-age=31536000; includeSubdomains; preload\" env=HTTPS | |
Header always set Public-Key-Pins \"pin-sha256=\\\"$HPKP\\\"; max-age=5184000\" | |
</IfModule> | |
SSLUseStapling on | |
SSLStaplingCache \"shmcb:logs/stapling_cache(128000)\" | |
<VirtualHost *:443> | |
ServerName $domain | |
ServerAlias www.$domain | |
ServerAdmin info@$domain | |
DocumentRoot /var/www/html | |
Header set Server \"Microsoft-IIS/4.0\" | |
XSendFile on | |
XSendFilePath /var/www/html/downloads/ | |
SetEnv COMPOSER_DISABLE_XDEBUG_WARN 1 | |
<IfModule mod_headers.c> | |
Header Always set Cache-Control \"max-age=0, no-cache, no-store, must-revalidate\" | |
Header Always set Pragma \"no-cache\" | |
</IfModule> | |
<Directory /var/www/html/> | |
Options -Indexes +FollowSymLinks | |
SSLRequireSSL | |
AllowOverride all | |
Require all granted | |
</Directory> | |
ErrorLog \${APACHE_LOG_DIR}/$domain-error.log | |
CustomLog \${APACHE_LOG_DIR}/$domain-access.log combined | |
SSLEngine on | |
# Intermediate configuration, tweak to your needs | |
SSLProtocol -all -SSLv3 +TLSv1.2 | |
SSLCipherSuite -LOW:AESGCM:AES:!kRSA:!kPSK:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!ADH | |
SSLStrictSNIVHostCheck Off | |
SSLCompression off | |
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire | |
SSLHonorCipherOrder on | |
# Add vhost name to log entries: | |
LogFormat \"%h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-agent}i\\\"\" vhost_combined | |
LogFormat \"%v %h %l %u %t \\\"%r\\\" %>s %b\" vhost_common | |
# Always ensure Cookies have \"Secure\" set (JAH 2012/1) | |
#Header edit Set-Cookie (?i)^(.*)(;\\s*secure)??((\\s*;)?(.*)) \"\$1; Secure\$3\$4\" | |
SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem | |
SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem | |
</VirtualHost> | |
</IfModule>" > /etc/apache2/sites-available/$domain-ssl.conf | |
a2dissite 000-default-le-ssl.conf | |
a2ensite $domain-ssl.conf | |
a2enmod proxy_fcgi xsendfile | |
service mysql stop | |
mv /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d.mysqld.original | |
echo "# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. | |
# | |
# This program is free software; you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation; version 2 of the License. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, write to the Free Software | |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
# | |
# The MySQL Server configuration file. | |
# | |
# For explanations see | |
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html | |
[mysqld] | |
pid-file = /var/run/mysqld/mysqld.pid | |
socket = /var/run/mysqld/mysqld.sock | |
datadir = /var/lib/mysql | |
log-error = /var/log/mysql/error.log | |
# By default we only accept connections from localhost | |
#bind-address = 127.0.0.1 | |
# Disabling symbolic-links is recommended to prevent assorted security risks | |
symbolic-links=0" > /etc/mysql/mysql.conf.d/mysqld.cnf | |
service mysql start | |
echo "MySQL Server Password" | |
mysql -u root -p mysql -e "create database wordpress; update user set Host=\"%\" where User=\"root\"; grant all privileges on *.* to 'root'@'%' with grant option; ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY ''; flush privileges;" | |
# get csf firewall | |
wget https://download.configserver.com/csf.tgz | |
tar xvf csf.tgz | |
cd csf | |
./install.sh | |
# update system | |
apt update -q -y && apt upgrade -q -y | |
# restart services | |
service php7.2-fpm restart | |
service mysql restart | |
service apache2 restart | |
# download and cleanup latest wordpress | |
rm -rf /var/www/html/index.html | |
cd /var/www/html/ | |
wget https://wordpress.org/latest.zip | |
unzip latest.zip | |
cp -R wordpress/* . | |
rm -rf wordpress | |
rm -rf latest.zip | |
rm -rf license.txt | |
rm -rf readme.html | |
rm -rf wp-config-sample.php | |
rm -rf wp-content/plugins/akismet | |
rm -rf wp-content/plugins/hello.php | |
mkdir wp-content/uploads | |
chown -R www-data: wp-content/uploads | |
# create .htaccess for wordpress | |
echo "Options -Indexes | |
# block rpc calls | |
<FilesMatch \"class-wp-xmlrpc-server\\.php|xmlrpc\\.php\"> | |
Deny from all | |
</FilesMatch> | |
# enable caching of media | |
<IfModule mod_expires.c> | |
ExpiresActive On | |
ExpiresByType image/jpg \"access 2 week\" | |
ExpiresByType image/jpeg \"access 2 week\" | |
ExpiresByType image/gif \"access 2 week\" | |
ExpiresByType image/png \"access 2 week\" | |
ExpiresByType text/css \"access 2 week\" | |
ExpiresByType application/pdf \"access 2 week\" | |
ExpiresByType text/x-javascript \"access 2 week\" | |
ExpiresByType application/x-shockwave-flash \"access 2 week\" | |
ExpiresByType image/x-icon \"access 2 week\" | |
ExpiresDefault \"access 2 week\" | |
</IfModule> | |
# compress images and scripts | |
<IfModule mod_gzip.c> | |
mod_gzip_on Yes | |
mod_gzip_dechunk Yes | |
mod_gzip_item_include file \\.(html?|txt|css|js|pl)\$ | |
mod_gzip_item_include handler ^cgi-script\$ | |
mod_gzip_item_include mime ^text/.* | |
mod_gzip_item_include mime ^application/x-javascript.* | |
mod_gzip_item_exclude mime ^image/.* | |
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.* | |
</IfModule> | |
<IfModule mod_deflate.c> | |
AddOutputFilterByType DEFLATE text/plain | |
AddOutputFilterByType DEFLATE text/html | |
AddOutputFilterByType DEFLATE text/css | |
AddOutputFilterByType DEFLATE application/javascript | |
AddOutputFilterByType DEFLATE application/x-javascript | |
</IfModule> | |
<IfModule mod_rewrite.c> | |
RewriteEngine On | |
RewriteRule ^system - [L] | |
RewriteRule ^index\\.php\$ - [L] | |
# Protect Wordpress Login - specify IP to allow | |
#RewriteCond %{REQUEST_URI} ^(.*)?wp-login\\.php(.*)\$ [OR] | |
#RewriteCond %{REQUEST_URI} ^(.*)?wp-admin\$ | |
#RewriteCond %{REMOTE_ADDR} !^123\\.123\\.123\\.74\$ | |
#RewriteRule ^(.*)\$ - [R=403,L] | |
# Handle robots.txt and sitemap.xml | |
RewriteRule ^sitemap.xml /sitemap.php?p=xml [L] | |
RewriteRule ^sitemap.xsl /sitemap.php?p=xsl [L] | |
RewriteRule ^sitemap.css /sitemap.php?p=css [L] | |
RewriteRule ^sitemap.js /sitemap.php?p=js [L] | |
RewriteRule ^robots.txt /sitemap.php?p=txt [L] | |
RewriteCond %{REQUEST_FILENAME} !-f | |
RewriteCond %{REQUEST_FILENAME} !-d | |
RewriteRule . /index.php [L] | |
</IfModule>" > .htaccess | |
# write wordpress config file | |
echo "<?php | |
/* Absolute path to the WordPress directory. */ | |
if ( !defined('ABSPATH') ) { define('ABSPATH', dirname(__FILE__) . '/'); } | |
/* Debug Mode */ | |
error_reporting(E_ALL); | |
@ini_set('display_errors', false ); | |
define( 'WP_DEBUG', false ); | |
define( 'WP_DEBUG_LOG', false ); | |
define( 'WP_DEBUG_DISPLAY', false ); | |
define( 'SCRIPT_DEBUG', false ); | |
define( 'SAVEQUERIES', false ); | |
/* set variables */ | |
\$table_prefix = 'wp_'; | |
\$use_ssl = true; | |
\$wp_content_root = 'wp-content'; | |
\$wp_content_uploads = \"{\$wp_content_root}/uploads\"; | |
\$wp_content_plugins = \"{\$wp_content_root}/plugins\"; | |
\$wp_content_plugins_mu = \"{\$wp_content_root}/plugins\"; | |
\$use_fsoverride = false; | |
\$use_ftpssh = false; | |
/* Database */ | |
define( 'DB_NAME', 'wordpress'); | |
define( 'DB_USER', 'root'); | |
define( 'DB_PASSWORD', ''); | |
define( 'DB_HOST', 'localhost'); | |
define( 'DB_CHARSET', 'utf8'); | |
define( 'DB_COLLATE', ''); | |
define( 'CUSTOM_USER_TABLE', \$table_prefix.'users' ); | |
define( 'CUSTOM_USER_META_TABLE', \$table_prefix.'usermeta' ); | |
/* Server and Paths */ | |
define( 'WP_SITEURL', (\$use_ssl ? 'https://' : 'http://') . \$_SERVER['HTTP_HOST'] ); | |
define( 'WP_HOME', WP_SITEURL); | |
define( 'UPLOADS', \$wp_content_uploads ); | |
define( 'WP_CONTENT_DIR', ABSPATH . \"/{\$wp_content_root}\" ); | |
define( 'WP_CONTENT_URL', WP_SITEURL . \"/{\$wp_content_root}\" ); | |
define( 'WP_PLUGIN_DIR', ABSPATH . \"/{\$wp_content_plugins}\" ); | |
define( 'WP_PLUGIN_URL', WP_SITEURL . \"/{\$wp_content_plugins}\" ); | |
define( 'WPMU_PLUGIN_DIR', ABSPATH . \"/{\$wp_content_plugins_mu}\" ); | |
define( 'WPMU_PLUGIN_URL', WP_SITEURL . \"/{\$wp_content_plugins_mu}\" ); | |
/* Cookies */ | |
define( 'COOKIEPATH', preg_replace( '|https?://[^/]+|i', '', WP_HOME . '/' ) ); | |
define( 'SITECOOKIEPATH', preg_replace( '|https?://[^/]+|i', '', WP_SITEURL . '/' ) ); | |
define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH . 'wp-admin' ); | |
define( 'PLUGINS_COOKIE_PATH', preg_replace( '|https?://[^/]+|i', '', WP_PLUGIN_URL ) ); | |
/* Restrict External Access */ | |
define( 'WP_HTTP_BLOCK_EXTERNAL', true ); | |
define( 'WP_ACCESSIBLE_HOSTS', \"{\$_SERVER['HTTP_HOST']},*.{\$_SERVER['HTTP_HOST']}\" ); | |
/* Cache */ | |
define( 'WP_CACHE', false ); | |
define( 'WP_CACHE_KEY_SALT', 'salt2018' ); | |
/* Languages */ | |
//define( 'WPLANG', 'en_CA' ); | |
//define( 'WP_LANG_DIR', ABSPATH . '/lang' ); | |
/* Options */ | |
define( 'DISABLE_WP_CRON', true ); | |
define( 'ALTERNATE_WP_CRON', false ); | |
define( 'WP_CRON_LOCK_TIMEOUT', 3600 ); | |
define( 'WP_POST_REVISIONS', 2 ); | |
define( 'DISALLOW_FILE_EDIT', true ); | |
define( 'DISALLOW_FILE_MODS', true ); | |
define( 'EMPTY_TRASH_DAYS', 0 ); | |
define( 'WP_MEMORY_LIMIT', '96M' ); | |
define( 'WP_MAX_MEMORY_LIMIT', '512M' ); | |
define( 'WP_ALLOW_MULTISITE', false ); | |
define( 'AUTOSAVE_INTERVAL', 600 ); | |
define( 'NOBLOGREDIRECT', WP_HOME ); | |
define( 'CONCATENATE_SCRIPTS', true ); | |
define( 'DISALLOW_UNFILTERED_HTML', true ); | |
define( 'IMAGE_EDIT_OVERWRITE', true ); | |
define( 'FORCE_SSL_ADMIN', \$use_ssl ); | |
define( 'WP_ALLOW_REPAIR', true ); | |
define( 'AUTOMATIC_UPDATER_DISABLED', true ); | |
define( 'WP_AUTO_UPDATE_CORE', false ); | |
/* Override File/Dir Permissions */ | |
if( \$use_fsoverride ) { | |
define( 'FS_CHMOD_DIR', ( 0515 & ~ umask() ) ); | |
define( 'FS_CHMOD_FILE', ( 0404 & ~ umask() ) ); | |
} | |
/* FTP/SSH OPTIONS */ | |
if( \$use_ftpssh ) { | |
// direct, ssh2, ftpext, ftpsockets | |
define( 'FS_METHOD', 'ssh2' ); | |
define( 'FTP_SSL', true ); | |
// hostname:port combo for your SSH/FTP server | |
define( 'FTP_HOST', '' ); | |
// absolute path to root installation directory | |
define( 'FTP_BASE', ABSPATH ); | |
define( 'FTP_CONTENT_DIR', WP_CONTENT_DIR ); | |
define( 'FTP_PLUGIN_DIR ', WP_PLUGIN_DIR ); | |
// absolute path to your SSH public key | |
define( 'FTP_PUBKEY', '../.ssh/id_rsa.pub' ); | |
define( 'FTP_PRIKEY', '../.ssh/id_rsa' ); | |
// either your FTP or SSH username | |
define( 'FTP_USER', '' ); | |
define( 'FTP_PASS', '' ); | |
} | |
/* Sets up WordPress vars and included files. */ | |
require_once(ABSPATH . 'wp-settings.php');" > wp-config.php | |
# setup CSF | |
cp /etc/csf/csf.conf /etc/csf/csf.conf.original | |
sed -i -E ' | |
s/^(TESTING *= *\")[^\"]*/\1'"0"'/g | |
s/^(VERBOSE *= *\")[^\"]*/\1'"0"'/g | |
s/^(SYSLOG *= *\")[^\"]*/\1'"0"'/g | |
s/^(URLGET *= *\")[^\"]*/\1'"2"'/g | |
s/^(DYNDNS *= *\")[^\"]*/\1'"300"'/g | |
s/^(DYNDNS_IGNORE *= *\")[^\"]*/\1'"1"'/g | |
s/^(UI *= *\")[^\"]*/\1'"0"'/g | |
s/^(RESTRICT_UI *= *\")[^\"]*/\1'"2"'/g | |
s/^(RESTRICT_SYSLOG *= *\")[^\"]*/\1'"3"'/g | |
s/^(LF_SPI *= *\")[^\"]*/\1'"1"'/g | |
s/^(IPV6 *= *\")[^\"]*/\1'"1"'/g | |
s/^(TCP_IN *= *\")[^\"]*/\1'"443"'/g | |
s/^(TCP6_IN *= *\")[^\"]*/\1'"443"'/g | |
s/^(TCP_OUT *= *\")[^\"]*/\1'"20:65534"'/g | |
s/^(TCP6_OUT *= *\")[^\"]*/\1'"1:65535"'/g | |
s/^(UDP_IN *= *\")[^\"]*/\1'""'/g | |
s/^(UDP6_IN *= *\")[^\"]*/\1'""'/g | |
s/^(UDP_OUT *= *\")[^\"]*/\1'"20:65534"'/g | |
s/^(UDP6_OUT *= *\")[^\"]*/\1'"1:65535,9999"'/g | |
s/^(ICMP_IN *= *\")[^\"]*/\1'"0"'/g | |
s/^(ICMP_OUT *= *\")[^\"]*/\1'"1"'/g | |
s/^(IGNORE_ALLOW *= *\")[^\"]*/\1'"0"'/g | |
s/^(LF_DAEMON *= *\")[^\"]*/\1'"1"'/g | |
s/^(LF_CSF *= *\")[^\"]*/\1'"1"'/g | |
s/^(LF_IPSET *= *\")[^\"]*/\1'"1"'/g | |
s/^(FASTSTART *= *\")[^\"]*/\1'"1"'/g | |
s/^(SMTP_BLOCK *= *\")[^\"]*/\1'"0"'/g | |
s/^(SMTP_ALLOWLOCAL *= *\")[^\"]*/\1'"1"'/g | |
s/^(CC_DENY *= *\")[^\"]*/\1'"AE,AF,AL,AR,AS,AZ,BA,BD,BE,BF,BH,BJ,BN,CI,CL,CN,CO,CS,DJ,EG,EH,ER,ES,ET,FR,GM,GN,GR,GW,HK,IQ,IR,IS,IT,JO,KG,KM,KO,KW,KZ,LB,LY,MC,MK,ML,MR,MV,MY,NE,NG,OM,PA,PE,PH,PK,PL,PS,QA,RS,RU,SA,SD,SG,SK,SL,SN,SO,SY,TD,TH,TJ,TM,TN,TR,UA,UZ,VN,XK,YE,YT"'/g | |
s/^(CC_ALLOW *= *\")[^\"]*/\1'""'/g | |
s/^(CC_LOOKUPS *= *\")[^\"]*/\1'"1"'/g | |
s/^(CC6_LOOKUPS *= *\")[^\"]*/\1'"1"'/g | |
s/^(IPV6_ICMP_STRICT *= *\")[^\"]*/\1'"1"'/g | |
' /etc/csf/csf.conf | |
echo "$dyndns" >> /etc/csf/csf.dyndns | |
echo "tcp:in:d=443:s=64.41.200.0/24" >> /etc/csf/csf.allow | |
# stop CSF if started | |
csf -x | |
# start CSF with new settings | |
csf -e | |
echo " | |
=========================================== | |
CONGRATULATIONS !!! | |
------------------------------------------- | |
MySQL, PHP7.2-FPM, Apache2, and your domain | |
are all ready to go with a letsencrypt cert | |
There is no password for MySQL currently, | |
and remote access is enabled for the dyndns | |
address you specified: | |
$dyndns | |
Make sure to create a database and non root | |
user in MySQL for Wordpress, then add the | |
database settings to: | |
/var/www/html/wp-config.php | |
If you have a static IP, you can uncomment | |
the lines pertaining to allowing access to | |
wp-admin from a specific IP address and | |
enter it in the format as shown. | |
After ready to run, open your webbrowser to | |
https://$domain/wp-admin/install.php | |
.. so you can finish setting up Wordpress. | |
=========================================== | |
" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment