-
-
Save phlbnks/37ef1f355ec5a7ecbb8f to your computer and use it in GitHub Desktop.
#!/bin/bash -e | |
clear | |
echo "============================================" | |
echo "WordPress Install Script" | |
echo "============================================" | |
echo "Do you need to setup new MySQL database? (y/n)" | |
read -e setupmysql | |
if [ "$setupmysql" == y ] ; then | |
echo "MySQL Admin User: " | |
read -e mysqluser | |
echo "MySQL Admin Password: " | |
read -s mysqlpass | |
echo "MySQL Host (Enter for default 'localhost'): " | |
read -e mysqlhost | |
mysqlhost=${mysqlhost:-localhost} | |
fi | |
echo "WP Database Name: " | |
read -e dbname | |
echo "WP Database User: " | |
read -e dbuser | |
echo "WP Database Password: " | |
read -s dbpass | |
echo "WP Database Table Prefix [numbers, letters, and underscores only] (Enter for default 'wp_'): " | |
read -e dbtable | |
dbtable=${dbtable:-wp_} | |
echo "Do basic hardening of wp-config and htaccess? (y/n)" | |
read -e harden | |
if [ "$harden" == y ] ; then | |
echo "Key for updating: " | |
read -e hardenkey | |
fi | |
echo "Last chance - sure you want to run the install? (y/n)" | |
read -e run | |
if [ "$run" == y ] ; then | |
if [ "$setupmysql" == y ] ; then | |
echo "============================================" | |
echo "Setting up the database." | |
echo "============================================" | |
#login to MySQL, add database, add user and grant permissions | |
dbsetup="create database $dbname;GRANT ALL PRIVILEGES ON $dbname.* TO $dbuser@$mysqlhost IDENTIFIED BY '$dbpass';FLUSH PRIVILEGES;" | |
mysql -u $mysqluser -p$mysqlpass -e "$dbsetup" | |
if [ $? != "0" ]; then | |
echo "============================================" | |
echo "[Error]: Database creation failed. Aborting." | |
echo "============================================" | |
exit 1 | |
fi | |
fi | |
echo "============================================" | |
echo "Installing WordPress for you." | |
echo "============================================" | |
#download wordpress | |
echo "Downloading..." | |
curl -O https://wordpress.org/latest.tar.gz | |
#unzip wordpress | |
echo "Unpacking..." | |
tar -zxf latest.tar.gz | |
#move /wordpress/* files to this dir | |
echo "Moving..." | |
mv wordpress/* ./ | |
echo "Configuring..." | |
#create wp config | |
mv wp-config-sample.php wp-config.php | |
#set database details with perl find and replace | |
perl -pi -e "s'database_name_here'"$dbname"'g" wp-config.php | |
perl -pi -e "s'username_here'"$dbuser"'g" wp-config.php | |
perl -pi -e "s'password_here'"$dbpass"'g" wp-config.php | |
perl -pi -e "s/\'wp_\'/\'$dbtable\'/g" wp-config.php | |
#set WP salts | |
perl -i -pe' | |
BEGIN { | |
@chars = ("a" .. "z", "A" .. "Z", 0 .. 9); | |
push @chars, split //, "!@#$%^&*()-_ []{}<>~\`+=,.;:/?|"; | |
sub salt { join "", map $chars[ rand @chars ], 1 .. 64 } | |
} | |
s/put your unique phrase here/salt()/ge | |
' wp-config.php | |
#create uploads folder and set permissions | |
mkdir wp-content/uploads | |
chmod 775 wp-content/uploads | |
if [ "$harden" == y ] ; then | |
echo "============================================" | |
echo "Hardening." | |
echo "============================================" | |
#remove readme.html | |
rm readme.html | |
#debug extras | |
perl -pi -e "s/define\('WP_DEBUG', false\);/define('WP_DEBUG', false);\n\/** Useful extras *\/ \nif (WP_DEBUG) { \n\tdefine('WP_DEBUG_LOG', true); \n\tdefine('WP_DEBUG_DISPLAY', false); \n\t\@ini_set('display_errors',0);\n}/" wp-config.php | |
# key access to mods | |
find="/* That's all, stop editing! Happy blogging. */" | |
replace="/** Disallow theme and plugin editor in admin. Updates only with query var */\ndefine( 'DISALLOW_FILE_EDIT', true );\nif ( \\$\_REQUEST['key'] == '$hardenkey' ) {\n\tsetcookie( 'updatebypass', 1 );\n} elseif ( ! \\$\_COOKIE['updatebypass'] ) {\n\tdefine( 'DISALLOW_FILE_MODS', true );\n}\n\n/* That's all, stop editing! Happy blogging. */" | |
perl -pi -e "s{\Q$find\E}{$replace}" wp-config.php | |
#create root .htaccess with some useful starters | |
cat > .htaccess <<'EOL' | |
# Protect this file | |
<Files ~ "^\.ht"> | |
Order allow,deny | |
Deny from all | |
</Files> | |
# Prevent directory listing | |
Options -Indexes | |
## BEGIN 6G Firewall from https://perishablepress.com/6g/ | |
# 6G:[QUERY STRINGS] | |
<IfModule mod_rewrite.c> | |
RewriteEngine On | |
RewriteCond %{QUERY_STRING} (eval\() [NC,OR] | |
RewriteCond %{QUERY_STRING} (127\.0\.0\.1) [NC,OR] | |
RewriteCond %{QUERY_STRING} ([a-z0-9]{2000}) [NC,OR] | |
RewriteCond %{QUERY_STRING} (javascript:)(.*)(;) [NC,OR] | |
RewriteCond %{QUERY_STRING} (base64_encode)(.*)(\() [NC,OR] | |
RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC,OR] | |
RewriteCond %{QUERY_STRING} (<|%3C)(.*)script(.*)(>|%3) [NC,OR] | |
RewriteCond %{QUERY_STRING} (\\|\.\.\.|\.\./|~|`|<|>|\|) [NC,OR] | |
RewriteCond %{QUERY_STRING} (boot\.ini|etc/passwd|self/environ) [NC,OR] | |
RewriteCond %{QUERY_STRING} (thumbs?(_editor|open)?|tim(thumb)?)\.php [NC,OR] | |
RewriteCond %{QUERY_STRING} (\'|\")(.*)(drop|insert|md5|select|union) [NC] | |
RewriteRule .* - [F] | |
</IfModule> | |
# 6G:[REQUEST METHOD] | |
<IfModule mod_rewrite.c> | |
RewriteCond %{REQUEST_METHOD} ^(connect|debug|delete|move|put|trace|track) [NC] | |
RewriteRule .* - [F] | |
</IfModule> | |
# 6G:[REFERRERS] | |
<IfModule mod_rewrite.c> | |
RewriteCond %{HTTP_REFERER} ([a-z0-9]{2000}) [NC,OR] | |
RewriteCond %{HTTP_REFERER} (semalt.com|todaperfeita) [NC] | |
RewriteRule .* - [F] | |
</IfModule> | |
# 6G:[REQUEST STRINGS] | |
<IfModule mod_alias.c> | |
RedirectMatch 403 (?i)([a-z0-9]{2000}) | |
RedirectMatch 403 (?i)(https?|ftp|php):/ | |
RedirectMatch 403 (?i)(base64_encode)(.*)(\() | |
RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\. | |
RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&?)/?$ | |
RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\") | |
RedirectMatch 403 (?i)(~|`|<|>|:|;|,|%|\\|\s|\{|\}|\[|\]|\|) | |
RedirectMatch 403 (?i)/(=|\$&|_mm|cgi-|etc/passwd|muieblack) | |
RedirectMatch 403 (?i)(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ) | |
RedirectMatch 403 (?i)\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$ | |
RedirectMatch 403 (?i)/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php | |
</IfModule> | |
# 6G:[USER AGENTS] | |
<IfModule mod_setenvif.c> | |
SetEnvIfNoCase User-Agent ([a-z0-9]{2000}) bad_bot | |
SetEnvIfNoCase User-Agent (archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune) bad_bot | |
<limit GET POST PUT> | |
Order Allow,Deny | |
Allow from All | |
Deny from env=bad_bot | |
</limit> | |
</IfModule> | |
# 6G:[BAD IPS] | |
<Limit GET HEAD OPTIONS POST PUT> | |
Order Allow,Deny | |
Allow from All | |
# uncomment/edit/repeat next line to block IPs | |
# Deny from 123.456.789 | |
</Limit> | |
## END 6G Firewall | |
## BEGIN htauth basic authentication | |
# STAGING | |
Require all denied | |
AuthType Basic | |
AuthUserFile /etc/apache2/wp-login | |
AuthName "Please Authenticate" | |
Require valid-user | |
# LIVE - prevent wp-login brute force attacks from causing load | |
#<FilesMatch "^(wp-login|xmlrpc)\.php$"> | |
# AuthType Basic | |
# AuthUserFile /etc/apache2/wp-login | |
# AuthName "Please Authenticate" | |
# Require valid-user | |
#</FilesMatch> | |
# Exclude the file upload and WP CRON scripts from authentication | |
#<FilesMatch "(async-upload\.php|wp-cron\.php)$"> | |
# Satisfy Any | |
# Order allow,deny | |
# Allow from all | |
# Deny from none | |
#</FilesMatch> | |
## END htauth | |
## BEGIN WP file protection | |
<Files wp-config.php> | |
order allow,deny | |
deny from all | |
</Files> | |
# WP includes directories | |
<IfModule mod_rewrite.c> | |
RewriteEngine On | |
RewriteBase / | |
RewriteRule ^wp-admin/includes/ - [F,L] | |
RewriteRule !^wp-includes/ - [S=3] | |
# note - comment out next line on multisite | |
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L] | |
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L] | |
RewriteRule ^wp-includes/theme-compat/ - [F,L] | |
</IfModule> | |
## END WP file protection | |
# Prevent author enumeration | |
RewriteCond %{REQUEST_URI} !^/wp-admin [NC] | |
RewriteCond %{QUERY_STRING} author=\d | |
RewriteRule ^ /? [L,R=301] | |
EOL | |
#create .htaccess to protect uploads directory | |
cat > wp-content/uploads/.htaccess <<'EOL' | |
# Protect this file | |
<Files .htaccess> | |
Order Deny,Allow | |
Deny from All | |
</Files> | |
# whitelist file extensions to prevent executables being | |
# accessed if they get uploaded | |
order deny,allow | |
deny from all | |
<Files ~ ".(docx?|xlsx?|pptx?|txt|pdf|xml|css|jpe?g|png|gif)$"> | |
allow from all | |
</Files> | |
EOL | |
fi | |
echo "Cleaning..." | |
#remove wordpress/ dir | |
rmdir wordpress | |
#remove zip file | |
rm latest.tar.gz | |
#remove bash script if it exists in this dir | |
[[ -f "wp.sh" ]] && rm "wp.sh" | |
echo "=========================" | |
echo "[Success]: Installation is complete." | |
echo "=========================" | |
else | |
exit | |
fi |
@maiorano84 - I haven't had time to test it yet, but this might do it: perl -pi -e "s/password_here/\Q$dbpass\E/g" wp-config.php
or perhaps perl -pi -e "s{password_here}{\Q$dbpass\E}g" wp-config.php
(they should be identical in function but the latter is a bit easier to read)
@maiorano84 @bgallagh3r If you're still using this / something similar and getting the 'special characters in passwords' problems, the latest revision should have that fixed now. Apparently using quotes as sed delimiters prevents interpretation of special characters. I'm still not preventing breaking characters being used in the user input, but it's a lot better than it was.
@emirpprime Nice job. I'm wondering, what are all you hardening ? Looks good, but I like to understand what I'm executing. :-)
Thanks.
@GabrielDancause sorry i missed your comment. Hardening will:
- disallow directly editing plugin / theme files in the admin area
- only allow plugin and core updates to be done if you supply the key (?key=YOUR_KEY_FOR_UPDATING); e.g. go to sites.com/wp-admin/?key=YOUR_KEY_FOR_UPDATING - then you will be able to update plugins etc.
- protect the .htaccess / .htpasswd and wp-config.php files
- remove a couple of files that tell people what version of WordPress you are running
- setup the 6G 'firewall' from Perishable Press
- prevent author enumeration
- stop people directly accessing the wp-includes directory
- only allow people to access certain file extensions in /uploads
It definitely needs some configuration for your setup. But it would run ok if you use it straight off as long as you either create a htpasswd file called wp-login and put it at /etc/apache2/ on your server, or just comment out the Staging section of the htauth config in the .htaccess file in the wordpress root directory.
Great script! Works on my Synology (XPEnology) DSM 5.2
Thank you both @emirpprime and @bgallagh3r
I am using this script to create a web app ...
To download and install wordpress..
i am new to shell..
(Problem 1) one thing i don't understand why you set db pass and local pass to null..
at first it works fine but now
(Problem 2) it does not read harden key and won't download and install wordpress ..
i am using this script to access localhost and after few tries my phpmyadmin won't allow me to access it.
(Problem 3) i have to uninstall and reinstall my server..
(Problem 4) though i managed to download wordpress and create database but it does not install wordpress and do not create tables in database..
(ignore grammar mistakes -- thank You :) )
same here, wordpress is downloaded & installed but tables are missing in the DB
This is a fantastic script. One oddity I've noticed and this occurs on both your version and bgallagh3r/wp.sh:
It seems like the password field being written to wp-config.php is stripping out meta characters. So if I enter a password that looks like: wordp355u$3r, the dollar sign and the character following it are stripped out becoming:
wordp355ur
I've tried something like:
perl -pi -e "s/password_here/\\Q${dbpass}/g" wp-config.php
But that doesn't solve the issue, and my Perl isn't very good. Any thoughts?