Skip to content

Instantly share code, notes, and snippets.

@simplesessions
Last active March 15, 2018 18:50
Show Gist options
  • Save simplesessions/7aa3fc531208c56f183e53beab0eb7f8 to your computer and use it in GitHub Desktop.
Save simplesessions/7aa3fc531208c56f183e53beab0eb7f8 to your computer and use it in GitHub Desktop.
Install PHP7 FPM, nginx mainline, mariaDB, iptables, Wordpress, WP-CLI
#### 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