Last active
March 15, 2018 18:50
-
-
Save simplesessions/7aa3fc531208c56f183e53beab0eb7f8 to your computer and use it in GitHub Desktop.
Install PHP7 FPM, nginx mainline, mariaDB, iptables, Wordpress, WP-CLI
This file contains 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
#### BEFORE USING THIS, CHANGE ALL THE VALUES BETWEEN DOUBLE-SQUARE-BRACKETS #### | |
# SEE THE END OF THIS FOR REFERENCES | |
# YOU SHOULD BE ABLE TO COPY AND PASTE THE FOLLOWING LINES, | |
# BUT CHUNK IT OUT BY THE # ===== separators | |
# PERFORM AS ROOT UNLESS OTHERWISE SPECIFIED | |
# ===== BEGIN INITIAL SETUP | |
sudo -i | |
timedatectl set-timezone [[timezone]] | |
wget http://nginx.org/keys/nginx_signing.key | |
apt-key add nginx_signing.key | |
touch /etc/apt/sources.list.d/nginx.list | |
echo deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx >> /etc/apt/sources.list.d/nginx.list | |
echo deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx >> /etc/apt/sources.list.d/nginx.list | |
apt-get install software-properties-common -y | |
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db | |
apt-get update | |
apt-get install nodejs nginx mariadb-server php-fpm php-mysql php-curl php-gd php-mbstring php-mcrypt php-xml php-xmlrpc php7.0-zip php7.0-gd postfix mailutils unzip fail2ban -y | |
# ===== | |
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar | |
chmod +x wp-cli.phar | |
sudo mv wp-cli.phar /usr/local/bin/wp | |
mkdir -p /var/www/[[site.com]]/wp | |
useradd deploy -s /bin/bash --gid www-data --no-create-home --home /var/www/[[site.com]] --password none | |
cp -R ~/.ssh /var/www/[[site.com]] | |
chmod 700 /var/www/[[site.com]]/.ssh/ | |
chmod 400 /var/www/[[site.com]]/.ssh/authorized_keys | |
chown -R deploy:www-data /var/www/[[site.com]] | |
passwd -l deploy | |
mkdir -p /var/lib/nginx | |
chown -R deploy:www-data /var/lib/nginx # see https://www.cubewebsites.com/blog/guides/fix-wordpress-on-nginx-err_incomplete_chunked_encoding/ | |
# ===== iptables to protect the server | |
iptables -F | |
iptables -P INPUT DROP | |
iptables -P FORWARD DROP | |
iptables -P OUTPUT DROP | |
iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT | |
iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT | |
iptables -A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A OUTPUT -p tcp --sport 80 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A OUTPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A INPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A OUTPUT -p tcp --sport 443 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A OUTPUT -p tcp --dport 25 -j ACCEPT | |
iptables -A OUTPUT -p tcp --dport 587 -j ACCEPT | |
iptables -A OUTPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -A INPUT -i lo -j ACCEPT | |
iptables -A OUTPUT -o lo -j ACCEPT | |
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT | |
iptables -A INPUT -p udp --sport 53 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 443 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT | |
iptables -N LOGGING | |
iptables -A INPUT -j LOGGING | |
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7 | |
iptables -A LOGGING -j DROP | |
sudo apt-get install iptables-persistent -y | |
# ===== Set up fail2ban | |
# http://xplus3.net/2013/05/09/securing-xmlrpc-wordpress/ | |
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local | |
cp /etc/fail2ban/filter.d/apache-badbots.conf /etc/fail2ban/filter.d/nginx-badbots.conf | |
echo "[Definition] | |
failregex = ^<HOST> -.*GET.*(\.php|\.asp|\.exe|\.pl|\.cgi|\.scgi) | |
ignoreregex =" > /etc/fail2ban/filter.d/nginx-noscript.conf | |
echo "[Definition] | |
failregex = ^<HOST> -.*GET .*/~.* | |
ignoreregex =" > /etc/fail2ban/filter.d/nginx-nohome.conf | |
echo "[Definition] | |
failregex = ^<HOST> -.*GET http.* | |
ignoreregex =" > /etc/fail2ban/filter.d/nginx-noproxy.conf | |
echo "[Definition] | |
failregex = ^<HOST> .*POST .*xmlrpc\.php.* | |
ignoreregex =" > /etc/fail2ban/filter.d/nginx-xmlrpc.conf | |
# TODO: easy way to insert fail2ban entries | |
# see https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04 | |
sudo vim /etc/fail2ban/jail.local | |
# ===== END INITIAL SETUP | |
# Configure Postfix | |
sudo vim /etc/postfix/main.cf | |
# change inet_interfaces = all to inet_interfaces = all to inet_interfaces = loopback-only | |
sudo service postfix restart | |
# Configure MySQL | |
mysql_secure_installation | |
mysql -u root -p -e 'CREATE DATABASE [[project_code]]; GRANT ALL ON [[project_code]].* to `[[project_code]]`@`localhost` identified by "[[db_password]]"' | |
# Configure Nginx | |
echo "server { | |
listen 80 default_server; # comment out after TLS setup | |
listen [::]:80 default_server; # comment out after TLS setup | |
# listen 443 ssl http2; # uncomment after TLS setup | |
server_name [[site.com]] www.[[site.com]]; | |
# uncomment the lines below after TLS setup | |
# ssl_certificate /etc/letsencrypt/live/[[site.com]]/fullchain.pem; | |
# ssl_certificate_key /etc/letsencrypt/live/[[site.com]]/privkey.pem; | |
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; | |
# ssl_prefer_server_ciphers on; | |
# ssl_dhparam /etc/ssl/certs/dhparam.pem; | |
# ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; | |
# ssl_session_timeout 1d; | |
# ssl_session_cache shared:SSL:50m; | |
# ssl_stapling on; | |
# ssl_stapling_verify on; | |
# add_header Strict-Transport-Security max-age=15768000; | |
root /var/www/[[site.com]]/wp; | |
index index.php index.html; | |
location / { | |
try_files \$uri \$uri/ /index.php\$is_args\$args; | |
} | |
location ~* ^/xmlrpc.php$ { | |
return 403; | |
} | |
gzip_static on; | |
gzip on; | |
gzip_disable "msie6"; | |
gzip_vary on; | |
gzip_proxied any; | |
gzip_comp_level 6; | |
gzip_buffers 16 8k; | |
gzip_http_version 1.1; | |
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml; | |
#error_page 404 /404.html; | |
# redirect server error pages to the static page /50x.html | |
# | |
error_page 500 502 503 504 /50x.html; | |
location = /50x.html { | |
root /usr/share/nginx/html; | |
} | |
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 | |
# | |
location ~ \.php$ { | |
include /etc/nginx/fastcgi_params; | |
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; | |
fastcgi_pass unix:/run/php/php7.0-fpm.sock; | |
} | |
location ~ /.well-known { | |
allow all; | |
} | |
location ~ /\.ht { | |
deny all; | |
} | |
location = /favicon.ico { log_not_found off; access_log off; } | |
location = /robots.txt { log_not_found off; access_log off; allow all; } | |
location ~* \.(css|gif|ico|jpeg|jpg|js|png|svg)$ { | |
expires max; | |
log_not_found off; | |
} | |
# FastCGI Buffers ---------------------------------------------------- | |
# Ref: https://gist.github.com/magnetikonline/11312172 | |
fastcgi_buffers 32 32k; | |
fastcgi_buffer_size 32k; | |
proxy_buffers 8 32k; | |
proxy_buffer_size 64k; | |
# Security (through obscurity) ---------------------------------------------------- | |
# Ref: https://en.wikipedia.org/wiki/Security_through_obscurity | |
# To hide nginx version | |
server_tokens off; | |
# To hide PHP version and other related fastcgi headers | |
fastcgi_hide_header X-Powered-By; | |
fastcgi_hide_header X-Pingback; | |
fastcgi_hide_header Link; | |
proxy_hide_header X-Powered-By; | |
proxy_hide_header X-Pingback; | |
proxy_hide_header X-Link; | |
# HSTS Protection ---------------------------------------------------- | |
add_header Strict-Transport-Security "max-age=31536000"; | |
add_header X-Content-Type-Options nosniff; | |
# please see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options | |
# add_header X-Frame-Options deny; | |
add_header X-Frame-Options SAMEORIGIN; | |
add_header X-XSS-Protection "1; mode=block"; | |
add_header Referrer-Policy "no-referrer-when-downgrade"; | |
# optional header - use it with care - you are warned! | |
# add_header Access-Control-Allow-Origin "*"; | |
# Global restrictions ---------------------------------------------------- | |
# Designed to be included in any server {} block. | |
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac), .git. | |
location /.git { deny all; } | |
location /.htaccess { deny all; } | |
location /.htpasswd { deny all; } | |
location /.user.ini { deny all; } | |
# this actually covers every dot file, except what follows below it (ex: CertBot) | |
location ~ ^/\. { deny all; } | |
# but allow CertBot - see http://stackoverflow.com/a/34262192 | |
location ^~ /.well-known/acme-challenge { | |
auth_basic off; | |
try_files $uri =404; | |
expires -1; | |
} | |
# Deny access to any files with a .php extension in the uploads directory | |
location ~* /uploads/.*\.php$ { deny all; } | |
# Deny access to any files with a .php extension in the uploads directory for multisite | |
location ~* /files/.*\.php$ { deny all; } | |
# Since version 2.5.7, Akismet introduced a new .htaccess file to block direct access to php files | |
# Ref: http://wordpress.org/extend/plugins/akismet/changelog/ | |
location ~* /akismet/.*\.php$ { deny all; } | |
# Restrict direct access to cached content | |
location /wp-content/cache/ { deny all; } | |
# Deny access to backup files! | |
location ~ ~$ { deny all; } | |
} | |
# uncomment the lines below after TLS setup. The return is set to 302 - change to 301 when site confirmed working as intended. | |
# server { | |
# listen 80; | |
# server_name [[site.com]] www.[[site.com]]; | |
# return 302 https://\$host\$request_uri; | |
# } | |
" > /etc/nginx/conf.d/[[site.com]].conf | |
mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.bak | |
vim /etc/nginx/nginx.conf | |
# user deploy www-data; | |
# worker_processes 2; | |
sudo service nginx restart | |
# Add this to the main nginx config | |
# server { | |
# listen 80 default_server; | |
# return 444; | |
# } | |
##--DO THIS--## PHP Path info fix - see https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-in-ubuntu-16-04 | |
vim /etc/php/7.0/fpm/php.ini | |
# cgi.fix_pathinfo=0 | |
vim /etc/php/7.0/fpm/pool.d/www.conf | |
# change in file under heading | |
# ; Unix user/group of processes | |
user = deploy | |
group = www-data | |
# restart PHP | |
systemctl restart php7.0-fpm | |
# ===== DO THE BELOW AS DEPLOY | |
echo "path: 'wp' | |
user: admin | |
url: 'http://[[server_ip]]' | |
color: true | |
debug: false | |
core config: | |
dbuser: [[project_code]] | |
dbpass: [[db_password]] | |
dbname: [[project_code]] | |
dbhost: 127.0.0.1 | |
dbprefix: [[random_prefix]]_ | |
dbcharset: utf8 | |
extra-php: | | |
define('WP_DEBUG', true); | |
define('WP_POST_REVISIONS', 10); | |
define('FS_METHOD', 'direct'); | |
core install: | |
title: [[site_title]] | |
admin_user: admin | |
admin_password: [[admin_password]] | |
admin_email: [[dev_email]]" > wp-cli.yml | |
wp core download | |
wp core config | |
wp core install | |
mv wp/wp-content . | |
cd ~/wp | |
ln -s ../wp-content . | |
cd ~ | |
mv wp/wp-config.php . | |
cd wp-content/plugins | |
wget https://github.com/wp-sync-db/wp-sync-db/archive/master.zip | |
wget https://github.com/wp-sync-db/wp-sync-db-media-files/archive/master.zip | |
unzip master.zip | |
unzip master.zip.1 | |
rm master.zip* | |
mv wp-sync-db-master wp-sync-db | |
mv wp-sync-db-media-files-master wp-sync-db-media-files | |
cd ~ | |
wp plugin activate wp-sync-db | |
wp plugin activate wp-sync-db-media-files | |
# ===== SSL SETUP - NO NEED TO PERFORM THIS FOR STAGING SERVERS | |
# ===== DO THE BELOW AS ROOT | |
# as root after pointing domain to server. ref: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04 | |
sudo -i | |
cd /usr/local/sbin | |
wget https://dl.eff.org/certbot-auto | |
chmod a+x /usr/local/sbin/certbot-auto | |
certbot-auto certonly -a webroot --webroot-path=/var/www/[[site.com]]/wp -d [[site.com]] -d www.[[site.com]] | |
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 | |
# as root, edit the nginx config for the site you just set up | |
vim /etc/nginx/conf.d/[[site.com]].conf | |
# when editing the file, just follow all the directions to comment and uncomment TLS-related config | |
service nginx restart | |
# set up auto-cert-renewal | |
crontab -e | |
## within the crontab | |
30 2 * * 1 /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log | |
35 2 * * 1 /etc/init.d/nginx reload | |
# ------------------------------------------------------------------- | |
# This Gist was compiled from the following sources: | |
# https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-in-ubuntu-16-04 | |
# https://github.com/pothi/wordpress-nginx/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment