Digital Ocean

Table of Contents

Set Up SSH Keys

Create the RSA key pair on the client machine

ssh-keygen -t rsa
Enter file in which to save the key (/home/demo/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):

Copy the Public Key

#1 use ssh-copy-id command
ssh-copy-id user@123.45.56.78
#2 use SSH
cat ~/.ssh/id_rsa.pub | ssh user@123.45.56.78 "cat >> ~/.ssh/authorized_keys"

[Optional] Disable the Password for Root Login

sudo nano /etc/ssh/sshd_config
#fine the line that includes PermitRootLogin and modify it
PermitRootLogin without-password
reload ssh

Setting up a new user1

Create a New User

adduser demo

add Root Privileges to the New User

visudo

# User privilege specification
root    ALL=(ALL:ALL) ALL
#Under there, add the following line, granting all the permissions to your new user
demo    ALL=(ALL:ALL) ALL

Configure SSH (OPTIONAL)

nano /etc/ssh/sshd_config
Port 25000
Protocol 2
PermitRootLogin no

PermitRootLogin: change this from yes to no to stop future root login. You will now only be logging on as the new user.

Add these lines to the bottom of the document, replacing demo in the AllowUsers line with your username. (AllowUsers will limit login to only the users on that line. To avoid this, skip this line):

UseDNS no
AllowUsers demo

Reload and Done

reload ssh
ssh -p 25000 demo@123.45.67.890

SFTP and SCP

SCP

scp ~/Downloads/backup_db.sql.gz username@server_ip_address:

SFTP

sftp username@remote_hostname_or_IP
#download files from our remote host
get remoteFile
#Transferring files to the remote system
put localFile

Security

How To Protect SSH with fail2ban on Ubuntu 12.042

How To Install DenyHosts on Ubuntu 12.043

How To Add Swap on Ubuntu 12.044

Check for Swap Space

sudo swapon -s
#An empty list will confirm that you have no swap files enabled:
Filename                                Type            Size    Used    Priority

Create and Enable the Swap File

1024*512k=512M swap space

sudo dd if=/dev/zero of=/swapfile bs=1024 count=512k
sudo mkswap /swapfile
#The results display:
Setting up swapspace version 1, size = 262140 KiB
no label, UUID=103c4545-5fc5-47f3-a8b3-dfbdb64fd7eb
#Finish up by activating the swap file:
sudo swapon /swapfile
#You will then be able to see the new swap file when you view the swap summary.
swapon -s
Filename                                Type            Size    Used    Priority
/swapfile                               file            262140  0       -1
#the swap is permanent by adding it to the fstab file
sudo nano /etc/fstab
#Paste in the following line:
 /swapfile       none    swap    sw      0       0

More Setting

Swappiness in the file should be set to 0. Skipping this step may cause both poor performance, whereas setting it to 0 will cause swap to act as an emergency buffer, preventing out-of-memory crashes.

You can do this with the following commands:

echo 0 | sudo tee /proc/sys/vm/swappiness
echo vm.swappiness = 0 | sudo tee -a /etc/sysctl.conf

To prevent the file from being world-readable, set up the correct permissions on the swap file:

sudo chown root:root /swapfile 
sudo chmod 0600 /swapfile

How To Install Linux, nginx, MySQL, PHP (LEMP) stack on Ubuntu 12.045

Update Apt-Get

sudo apt-get update

Install MySQL

sudo apt-get install mysql-server mysql-client
  • configuration

    Once you have installed MySQL, we should activate it with this command:

    sudo mysql_install_db
    

    Finish up by running the MySQL set up script:

    sudo /usr/bin/mysql_secure_installation
    

    It’s easiest just to say Yes to all the options. At the end, MySQL will reload and implement the new changes.

    By default, a MySQL installation has an anonymous user, allowing anyone
    to log into MySQL without having to have a user account created for
    them.  This is intended only for testing, and to make the installation
    go a bit smoother.  You should remove them before moving into a
    production environment.
    
    Remove anonymous users? [Y/n] y                                            
     ... Success!
    
    Normally, root should only be allowed to connect from 'localhost'.  This
    ensures that someone cannot guess at the root password from the network.
    
    Disallow root login remotely? [Y/n] y
    ... Success!
    
    By default, MySQL comes with a database named 'test' that anyone can
    access.  This is also intended only for testing, and should be removed
    before moving into a production environment.
    
    Remove test database and access to it? [Y/n] y
     - Dropping test database...
     ... Success!
     - Removing privileges on test database...
     ... Success!
    
    Reloading the privilege tables will ensure that all changes made so far
    will take effect immediately.
    
    Reload privilege tables now? [Y/n] y
     ... Success!
    
    Cleaning up...
    

Install nginx

sudo apt-get install nginx

start nginx

sudo service nginx start

You can confirm that nginx has installed an your web server by directing your browser to your IP address. You can run the following command to reveal your VPS's IP address.

ifconfig eth0 | grep inet | awk '{ print $2 }'

Install PHP

sudo apt-get install php5-fpm
sudo apt-get install php5-mysql php5-gd php5-xdebug php-apc

php5-gd: This package provides a module for handling graphics directly from PHP scripts. It supports the PNG, JPEG, XPM formats as well as Freetype/ttf fonts.

More:

  • APC (php-pecl-apc) – APC caches and optimizes PHP intermediate code
  • CLI (php-cli) – Command-line interface for PHP
  • PEAR (php-pear) – PHP Extension and Application Repository framework
  • PDO (php-pdo) – A database access abstraction module for PHP applications
  • MySQL (php-mysqlnd) – A module for PHP applications that use MySQL databases
  • PostgreSQL (php-pgsql) – A PostgreSQL database module for PHP
  • MongoDB (php-pecl-mongo) – PHP MongoDB database driver
  • SQLite (php-sqlite) – Extension for the SQLite V2 Embeddable SQL Database Engine
  • Memcache (php-pecl-memcache) – Extension to work with the Memcached caching daemon
  • Memcached (php-pecl-memcached) – Extension to work with the Memcached caching daemon
  • GD (php-gd) – A module for PHP applications for using the gd graphics library
  • XML (php-xml) – A module for PHP applications which use XML
  • MBString (php-mbstring) – A module for PHP applications which need multi-byte string handling
  • MCrypt (php-mcrypt) – Standard PHP module provides mcrypt library support

Configure php

sudo nano /etc/php5/fpm/php.ini
cgi.fix_pathinfo=0

Find the line, cgi.fixpathinfo=1, and change the 1 to 0.

If this number is kept as 1, the php interpreter will do its best to process the file that is as near to the requested file as possible. This is a possible security risk. If this number is set to 0, conversely, the interpreter will only process the exact file path—a much safer alternative.

We need to make another small change in the php5-fpm configuration.

sudo nano /etc/php5/fpm/pool.d/www.conf
listen = /var/run/php5-fpm.sock
sudo service php5-fpm restart

Configure nginx

sudo nano /etc/nginx/sites-available/default

server {
        listen   80;

        root /usr/share/nginx/www;
        index index.html index.htm index.php;

        server_name yourdomain.com www.yourdomain.com;

        location / {
                #try to find the requested uri or redirect to index.php with request args
                try_files $uri $uri/ /index.php?$args;
        }

        error_page 404 /404.html;

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
                root /usr/share/nginx/www;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                include fastcgi_params;
        }

}

Create a php Info Page for Test[option]

sudo nano /usr/share/nginx/www/info.php
#Add in the following line:
<?php
phpinfo();
?>
#Restart nginx
sudo service nginx restart
#visiting http://youripaddress/info.php

Migrate Wordpress to Nginx6, 7

Restore Database

mysql -u root -p
CREATE DATABASE wordpress;
CREATE USER wordpressuser@localhost;
SET PASSWORD FOR wordpressuser@localhost= PASSWORD("password");
GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost;
FLUSH PRIVILEGES;
mysql -h localhost -u wordpressuser  -p wordpress < ./wordpress.sql

Basic NGINX Optimization

Increase or decrease the number of workers depending on your system's specs:

sudo nano /etc/nginx/nginx.conf
worker_processes 1;
#NGINX limits the number of connections that a worker can maintain at one time, if your websites have many visitors you might want to increase the limit of connections
worker_connections 768;
#Enabling Gzip
gzip on;
gzip_types text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon;

Files can be compressed using Gzip to accelerate WordPress, the smaller the data size requested by the user, the faster the response. Think about CSS files & HTML files, they have many similar strings, repeated text and white spaces.

Creating NGINX .conf files

create 3 files that will hold our configurations:

  • common.conf: Configurations applicable to all sites.
  • wordpress.conf: Configurations applicable to all WordPress sites.
  • multisite.conf: Special configurations for WordPress multisite with sub-directories.
  • create the dir
    sudo mkdir /etc/nginx/global
    cd /etc/nginx/global
    
  • common.conf file
    sudo nano common.conf
    
    # Global configuration file.
    # ESSENTIAL : Configure Nginx Listening Port
    listen 80;
    # ESSENTIAL : Default file to serve. If the first file isn't found, 
    index index.php index.html index.htm;
    # ESSENTIAL : no favicon logs
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
    # ESSENTIAL : robots.txt
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }
    # ESSENTIAL : Configure 404 Pages
    error_page 404 /404.html;
    # ESSENTIAL : Configure 50x Pages
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/share/nginx/www;
        }
    # SECURITY : Deny all attempts to access hidden files .abcde
    location ~ /\. {
        deny all;
    }
    # PERFORMANCE : Set expires headers for static files and turn off logging.
    location ~* ^.+\.(js|css|swf|xml|txt|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
        access_log off; log_not_found off; expires 30d;
    }
    

    location = /robots.txt {allow all;} allows the access to robots.txt, if you want to specify another directory for the robots.txt you can add an alias:

    location /robots.txt {
        alias /var/www/example.com/public/sample_robots.txt;
    }
    

    location ~ /\. {deny all;} in the Linux operating system a hidden file begins with a ".", access to some hidden files, such as .htaccess, should be blocked for security reasons.

    location ~* ^.+\.(js|css|swf... expires headers tell the browser whether they should request a specific file from the server or whether they should grab it from the browser's cache. With expires 30d we are telling the browser to store static files such as pictures for 30 days.

  • wordpress.conf file
    sudo nano wordpress.conf
    
    # WORDPRESS : Rewrite rules, sends everything through index.php and keeps the appended query string intact
    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }
    
    # SECURITY : Deny all attempts to access PHP Files in the uploads directory
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }
    # REQUIREMENTS : Enable PHP Support
    location ~ \.php$ {
        # SECURITY : Zero day Exploit Protection
        try_files $uri =404;
        # ENABLE : Enable PHP, listen fpm sock
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
    

    try_files $uri $uri/ /index.php?q=$uri&$args rewrite rule required to allow you to choose your custom permalink structure on WordPress.

    location ~* /(?:uploads|files)/.*\.php$ {deny all;} this will prevent malicious code from being uploaded and executed from the WordPress media directory.

    location ~ \.php$ {...} since WordPress is a php site, we need to tell NGINX how to a pass our php scripts to PHP5.

    try_files $uri =404; this is a security rule, you only want to either serve a determined php file or go to a 404 error.

  • multisite.conf file
    sudo nano multisite.conf
    
    # Rewrite rules for WordPress Multi-site.
    if (!-e $request_filename) {
    rewrite /wp-admin$ $scheme://$host$uri/ permanent;
    rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
    rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;
    }
    

Creating Server Blocks

Have two blogs: blog.dreamrunner.org and other.dreamrunner.org.

#disable the default server block:
sudo rm /etc/nginx/sites-enabled/default

#And create a server block file:
sudo nano /etc/nginx/sites-available/dreamrun

Add:

server {
    server_name blog.dreamrunner.org;
    root /home/shougang/www/laogangzhi;
    access_log /var/log/nginx/blog.dreamrunner.org.access.log;
    error_log /var/log/nginx/blog.dreamrunner.org.error.log;
    include global/common.conf;
    include global/wordpress.conf;
    include global/multisite.conf;
}

server {
    server_name other.dreamrunner.org;
    root /home/shougang/www/dreamrunner;
    access_log /var/log/nginx/other.dreamrunner.org.access.log;
    error_log /var/log/nginx/other.dreamrunner.org.error.log;
    include global/common.conf;
    include global/wordpress.conf;
    include global/multisite.conf;
}
  • server_name: Determine which server block is used for a given URL.
  • root: The path where your site is stored.
  • access log & error log: Set the paths for your logs

Restore Wordpress Files

Copy the Wordpress files to /home/username/www/ and upzip;

sudo chown www-data:www-data * -R 
sudo usermod -a -G www-data [username]
#in the wp-config.php file add
define( 'FS_METHOD', 'direct' )

MySQL Tips

list MySQL user

SELECT User FROM mysql.user;

Create and Delete a MySQL Database

SHOW DATABASES;
CREATE DATABASE database name;
DROP DATABASE database name;

Access a MySQL Database

USE events;
SHOW tables;

Create a MySQL Table

CREATE TABLE potluck (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
name VARCHAR(20),
food VARCHAR(30),
confirmed CHAR(1), 
signup_date DATE);
#the table’s organization with this command:
DESCRIBE potluck;

Add Information to a MySQL Table

INSERT INTO `potluck` (`id`,`name`,`food`,`confirmed`,`signup_date`) VALUES (NULL, "John", "Casserole","Y", '2012-04-11');
SELECT * FROM potluck;

Update Information in the Table

UPDATE `potluck` 
SET 
`confirmed` = 'Y' 
WHERE `potluck`.`name` ='Sandy';

Add and Delete a Column

ALTER TABLE potluck ADD email VARCHAR(40);
# place that column in a specific spot in the table
ALTER TABLE potluck ADD email VARCHAR(40) AFTER name; 
ALTER TABLE potluck DROP email;

Delete a Row

DELETE from [table name] where [row name]=[field text];

How To Create a SSL Certificate on nginx for Ubuntu 12.04

Create a Directory for the Certificate

The SSL certificate has 2 parts main parts: the certificate itself and the public key.

sudo mkdir /etc/nginx/ssl
cd /etc/nginx/ssl

Create the Server Key and Certificate Signing Request

Start by creating the private server key. During this process, you will be asked to enter a specific passphrase. Be sure to note this phrase carefully, if you forget it or lose it, you will not be able to access the certificate.

sudo openssl genrsa -des3 -out server.key 1024
#Follow up by creating a certificate signing request:
sudo openssl req -new -key server.key -out server.csr

This command will prompt terminal to display a lists of fields that need to be filled in.

The most important line is "Common Name". Enter your official domain name here or, if you don't have one yet, your site's IP address. Leave the challenge password and optional company name blank.

Remove the Passphrase

However, it would serve us to remove the passphrase. Although having the passphrase in place does provide heightened security, the issue starts when one tries to reload nginx. In the event that nginx crashes or needs to reboot, you will always have to re-enter your passphrase to get your entire web server back online.

sudo cp server.key server.key.org
sudo openssl rsa -in server.key.org -out server.key

Sign your SSL Certificate

Keep in mind that you can specify how long the certificate should remain valid by changing the 365 to the number of days you prefer. As it stands this certificate will expire after one year.

sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Set Up the Certificate for Test [option]

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example
sudo nano /etc/nginx/sites-available/example

# HTTPS server
server {
        listen 443;
        server_name example.com;

        root /usr/share/nginx/www;
        index index.html index.htm;

        ssl on;
        ssl_certificate /etc/nginx/ssl/server.crt;
        ssl_certificate_key /etc/nginx/ssl/server.key; 
}

Activate the Virtual Host

sudo ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example
sudo service nginx restart

Nginx and PHP5-FPM Configuration and Optimizing Tips

high memory of php5-fpm

搬移到512M的digitalocean, Nginx + PHP5-FPM + Wordpress, 发现PHP5-FPM 的memory占用很高。

$ ps -A --sort -rss -o comm,pmem,pcpu | uniq -c | head -15
      1 COMMAND         %MEM %CPU
      1 php5-fpm        21.2  0.0
      1 php5-fpm        21.1  0.0
      1 php5-fpm        19.3  0.0
      1 php5-fpm        17.9  0.0
      1 php5-fpm        17.4  0.0
      1 php5-fpm        16.4  0.0
      1 bash             1.5  4.2
      1 php5-fpm         0.6  0.0
      1 rsyslogd         0.6  0.0
      1 nginx            0.5  0.0
      1 init             0.2  0.0
      1 sshd             0.2  0.1
      1 whoopsie         0.2  0.0
      1 nginx            0.2  0.0

$ free
             total       used       free     shared    buffers     cached
Mem:        502740     476344      26396          0       1120      50460
-/+ buffers/cache:     424764      77976
Swap:       524284          0     524284

Nginx

  • Organize Nginx Configuration Files
    ## Main configuration file ##
    /etc/nginx/nginx.conf
    
    ## Virtualhost configuration files on ##
    /etc/nginx/sites-available/
    /etc/nginx/sites-enabled/
    
    ## Other config files on (if needed) ##
    /etc/nginx/conf.d/
    
  • nginx.conf
    worker_processes [number of processor cores];
    
    cat /proc/cpuinfo |grep processor
    processor       : 0
    
    worker_processes 1;
    
  • under /etc/nginx/conf.d/

    create user.conf:

    #The charset directive will not only cause Nginx to re-encode 
    #anything that is not in the defined character set, 
    #it will also add it to the Content-Type HTTP header so browsers know.
    charset utf-8;
    
    #The default Nginx client_max_body_size is 1mb. 
    #That’s too small for most everything these days
    client_max_body_size 32m;
    client_body_buffer_size 128k;
    
    #Hide Nginx Server Tokens / Hide Nginx version number
    server_tokens off;
    

    create ssl.conf

    # we want to enable ssl session resumption to avoid
    # having to start the handshake from scratch each page load
    # so first we enable a shared cache, named SSL (creative!) that is 10mb large
    ssl_session_cache shared:SSL:10m;
    
    # save things in the cache for 3 minutes
    # if you're not making a request at least every 3 minutes, this isn't going
    # to accomplish anything anyway
    ssl_session_timeout 3m;
    
    # now we're going to change a bunch related to SSL ciphers and protocol
    # the primary goal here is to be more secure, and i've generally tried to
    # go with things that comply with the Federal Information Processing Standard (FIPS)
    # set by the US government for non-military government use
    
    # we don't want to support SSLv3, it's known to be insecure
    # FIPS 140-2 compliance, TLS1+ only
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
    # now we go through a couple different options for the SSL ciphers to support, mainly just to
    # give you a bunch of options to pick from
    
    # this is a very concise definition of ciphers that don't allow anonymous DH or MD5 - the big weaknesses
    #       per: https://calomel.org/nginx.html
    #ssl_ciphers HIGH:!ADH!MD5:@STRENGTH;
    
    # this is a very (not so) short list of very secure ciphers that may be incompatible with older browsers
    #       per: https://calomel.org/nginx.html 
    #ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:AES128-SHA;
    
    # this excludes insecure ciphers and sorts the others by strength
    # it is BEAST-resistant, prioritizing RC4
    #       per: http://groups.drupal.org/node/179344
    #ssl_ciphers !aNULL:!LOW:!MD5:!EXP:RC4:CAMELLIA:AES128:3DES:SEED:AES256@STRENGTH;
    
    # this is a combination of everything above and openssl docs - very secure, FIPS-compliant, ordered by strength
    ssl_ciphers !aNULL:!eNULL:FIPS@STRENGTH;
    
    # don't let the client decide what ciphers to use, we've told the server which to allow
    ssl_prefer_server_ciphers on;
    

PHP5-FPM

  • the Configuration Files
    ## Main configuration file ##
    /etc/php5/fpm/php-fpm.conf
    
    ## last line of php-fpm.conf:include=/etc/php5/fpm/pool.d/*.conf
    ## Other config files on (if needed) ##
    /etc/php5/fpm/pool.d/
    
  • pool.d/www.conf
    pm.max_children = 5
    pm.start_servers = 2
    pm.min_spare_servers = 1
    pm.max_spare_servers = 3
    listen = /var/run/php5-fpm.socket
    

Footnotes:

Author: Shi Shougang

Created: 2015-03-05 Thu 23:19

Emacs 24.3.1 (Org mode 8.2.10)

Validate