Saturday, December 5, 2015

Additional Server Setup

Firewall

Add the ufw firewall and open only those ports needed to serve web pages.

Allow SSH access to the server
sudo ufw allow ssh

Allow TCP access on port 80
sudo ufw allow 80/tcp

Allow TCP access on port 443 (https)
sudo ufw allow 443/tcp

Enable ufw
sudo ufw enable 

Check the ufw status
sudo ufw show added

Timezone Configuration

Set the timezone for your server to where you live.
sudo dpkg-reconfigure tzdata

Select your Country
Select your State/Provence 

Install NTP 

NTP is automatic time adjustment.
sudo apt-get update

sudo apt-get install ntp

It will automatically start the service and restart it if the server needs rebooting.

Add SwapFile

Swap file is where the operating system stores less often used commands usually kept in RAM. It's merely a precaution to add a swapfile to prevent server crash in the event it runs out of memory.

Make the swap file that same size as the total RAM on the system. 1G of RAM requires a 1G swapfile.

Allocate a gig of space for the swapfile
sudo fallocate -l 1G /swapfile

Change access permission for the swapfile
sudo chmod 600 /swapfile

Tell the OS to make the /swapfile a swapfile
sudo mkswap /swapfile

Turn the swap file on
sudo swapon /swapfile

Set up the system so that the swapfile is turned on a reboot
sudo sh -c 'echo "/swapfile none swap sw 0 0" >> /etc/fstab'

Friday, November 6, 2015

Removing Stuff

Once a bunch of stuff is installed and plans change, how do you back out cleanly and start again.

Apache2

  • sudo service apache2 stop
  • sudo apt-get remove --purge apache2
[note: remove removes the application and --purge removes configuration files]

MySQL
  • sudo service mysql stop
  • sudo apt-get remove --purge mysql-common mysql-server
PHP
Crazy powerful command. You may want to be more specific.
  • sudo apt-get remove "php*"
More specific long list of packages may be more appropriate. Edit as necessary. This is probably not a conprehensive list. I should update with sets of commonly used and grouped packages.
  • sudo apt-get remove --purge php-pear php5-cli php5-common php5-curl php5-fpm php5-gd php5-intl php5-mysql php5-pspell php5-readline php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl
Need to know what packages you already have installed?
  • dpkg --get-selections | grep -v deinstall

Tuesday, October 27, 2015

Preparing the server for Wordpress Multisite

Install Nginx
  1. sudo apt-get update
  2. sudo apt-get install nginx
Install MySQL DB
  1. sudo apt-get install mysql-server
  2. sudo mysql_install_db
  3. sudo mysql_secure_installation
    • Set password for root if you haven't already. If you have a password, type n for no.
    • Remove Anonymous Users: Press Enter to select default Yes
    • Disallow root login: Press Enter to select default Yes
    • Remove test database and access to it: Press Enter to select default Yes
    • Reload Privilege tables now: Press Enter to select default Yes
Install PHP
  1. sudo apt-get install php5-fpm php5-mysql
  2. sudo nano /etc/php5/fpm/php.ini
    • uncomment ;cgi.fix_pathinfo=0 and set value equal to zero.
  1. sudo service php5-fpm restart


Digital Ocean Prerequisites
Read:


LAMP Stack Security

We're getting ready to go live with a new product and I wanted to be sure I understood how to chmod/chown/chgrp files and directories on the prod server to have a secure product that was maintainable by a small team of people. I found this post on ServerFault.com. Probably not complete or broadly applicable, but it's a good start.




When deciding what permissions to use, you need to know exactly who your users are and what they need. A webserver interacts with two types of user.
Authenticated users have a user account on the server and can be provided with specific privileges. This usually includes system administrators, developers, and service accounts. They usually make changes to the system using SSH or SFTP.
Anonymous users are the visitors to your website. Although they don't have permissions to access files directly, they can request a web page and the web server acts on their behalf. You can limit the access of anonymous users by being careful about what permissions the web server process has. On many Linux distributions, Apache runs as the www-data user but it can be different. Use ps aux | grep httpd or ps aux | grep apache to see what user Apache is using on your system.

Notes on linux permissions

Linux and other POSIX-compliant systems use traditional unix permissions. There is an excellent article on Wikipedia about Filesystem permissions so I won't repeat everything here. But there are a few things you should be aware of.
The execute bit
Interpreted scripts (eg. Ruby, PHP) work just fine without the execute permission. Only binaries and shell scripts need the execute bit. In order to traverse (enter) a directory, you need to have execute permission on that directory. The webserver needs this permission to list a directory or serve any files inside of it.
Default new file permissions
When a file is created, it normally inherits the group id of whoever created it. But sometimes you want new files to inherit the group id of the folder where they are created, so you would enable the SGID bit on the parent folder.
Default permission values depend on your umask. The umask subtracts permissions from newly created files, so the common value of 022 results in files being created with 755. When collaborating with a group, it's useful to change your umask to 002 so that files you create can be modified by group members. And if you want to customize the permissions of uploaded files, you either need to change the umask for apache or run chmod after the file has been uploaded.

The problem with 777

When you chmod 777 your website, you have no security whatsoever. Any user on the system can change or delete any file in your website. But more seriously, remember that the web server acts on behalf of visitors to your website, and now the web server is able to change the same files that it's executing. If there are any programming vulnerabilities in your website, they can be exploited to deface your website, insert phishing attacks, or steal information from your server without you ever knowing.

Define the requirements

  • Developers need read/write access to files so they can update the website
  • Developers need read/write/execute on directories so they can browse around
  • Apache needs read access to files and interpreted scripts
  • Apache needs read/execute access to serveable directories
  • Apache needs read/write/execute access to directories for uploaded content

Maintained by a single user

If only one user is responsible for maintaining the site, set them as the user owner on the website directory and give the user full rwx permissions. Apache still needs access so that it can serve the files, so set www-data as the group owner and give the group r-x permissions.
chown -R eve contoso.com
chgrp -R www-data contoso.com
chmod -R 750 contoso.com
chmod g+s contoso.com
ls -l
drwxr-s--- 2 eve      www-data   4096 Feb  5 22:52 contoso.com
If you have folders that need to be writable by Apache, you can just modify the permission values for the group owner so that www-data has write access.
chmod g+w uploads
ls -l
drwxrws--- 2 eve      www-data   4096 Feb  5 22:52 uploads
The benefit of this configuration is that it becomes harder (but not impossible*) for other users on the system to snoop around, since only the user and group owners can browse your website directory. This is useful if you have secret data in your configuration files. Be careful about your umask! If you create a new file here, the permission values will probably default to 755. You can run umask 027 so that new files default to 640 (rw- r-- ---).

Maintained by a group of users

If more than one user is responsible for maintaining the site, you will need to create a group to use for assigning permissions. It's good practice to create a separate group for each website, and name the group after that website.
groupadd dev-fabrikam
usermod -a -G dev-fabrikam alice
usermod -a -G dev-fabrikam bob
In the previous example, we used the group owner to give privileges to Apache, but now that is used for the developers group. Since the user owner isn't useful to us any more, setting it to root is a simple way to ensure that no privileges are leaked. Apache still needs access, so we give read access to the rest of the world.
chown -R root fabrikam.com
chgrp -R dev-fabrikam fabrikam.com
chmod -R 775 fabrikam.com
chmod g+s fabrikam.com
ls -l
drwxrwxr-x 2 root     dev-fabrikam   4096 Feb  5 22:52 fabrikam.com
If you have folders that need to be writable by Apache, you can make Apache either the user owner or the group owner. Either way, it will have all the access it needs. Personally, I prefer to make it the user owner so that the developers can still browse and modify the contents of upload folders.
chown -R www-data uploads
ls -l
drwxrwxr-x 2 www-data     dev-fabrikam   4096 Feb  5 22:52 uploads
Although this is a common approach, there is a downside. Since every other user on the system has the same privileges to your website as Apache does, it's easy for other users to browse your site and read files that may contain secret data, such as your configuration files.
You can have your cake and eat it too
This can be futher improved upon. It's perfectly legal for the owner to have less privileges than the group, so instead of wasting the user owner by assigning it to root, we can make Apache the user owner on the directories and files in your website. This is a reversal of the single maintainer scenario, but it works equally well.
chown -R www-data fabrikam.com
chgrp -R dev-fabrikam fabrikam.com
chmod -R 570 fabrikam.com
chmod g+s fabrikam.com
ls -l
dr-xrwx--- 2 www-data  dev-fabrikam   4096 Feb  5 22:52 fabrikam.com
If you have folders that need to be writable by Apache, you can just modify the permission values for the user owner so that www-data has write access.
chmod u+w uploads
ls -l
drwxrwx--- 2 www-data  dev-fabrikam   4096 Feb  5 22:52 fabrikam.com
One thing to be careful about with this solution is that the user owner of new files will match the creator instead of being set to www-data. So any new files you create won't be readable by Apache until you chown them.

*Apache privilege separation

I mentioned earlier that it's actually possible for other users to snoop around your website no matter what kind of privileges you're using. By default, all Apache processes run as the same www-data user, so any Apache process can read files from all other websites configured on the same server, and sometimes even make changes. Any user who can get Apache to run a script can gain the same access that Apache itself has.
To combat this problem, there are various approaches to privilege separation in Apache. However, each approach comes with various performance and security drawbacks. In my opinion, any site with higher security requirements should be run on a dedicated server instead of using VirtualHosts on a shared server.

Additional considerations

I didn't mention it before, but it's usually a bad practice to have developers editing the website directly. For larger sites, you're much better off having some kind of release system that updates the webserver from the contents of a version control system. The single maintainer approach is probably ideal, but instead of a person you have automated software.
If your website allows uploads that don't need to be served out, those uploads should be stored somewhere outside the web root. Otherwise, you might find that people are downloading files that were intended to be secret. For example, if you allow students to submit assignments, they should be saved into a directory that isn't served by Apache. This is also a good approach for configuration files that contain secrets.
For a website with more complex requirements, you may want to look into the use of Access Control Lists. These enable much more sophisticated control of privileges.
If your website has complex requirements, you may want to write a script that sets up all of the permissions. Test it thoroughly, then keep it safe. It could be worth its weight in gold if you ever find yourself needing to rebuild your website for some reason.

Lessons Learned in Linux Command Line

Need a place to put command line coolness I've stumbled across.

Returns the number of files found recursively. 
find . -type f | wc -l

I needed to know the total number of image files in our project.

Sunday, February 22, 2015

For My Next Trick

For my next post, I'll write about recovering from breaking SUDO.

Hint: there is no recovering, just reinstalling.

Wednesday, January 21, 2015

Adding Apache Behind Nginx

I saw this article by Karl Blessing (kbezzie.com) about letting Nginx do what it's good at, but passing back to Apache everything PHP, mod_rewrite, and htaccess, since that's something it's good at. I ran across this article when I was trying to configure Nginx to run a PHP interpreter and perform mod_rewrite-like tasks for a content management system, not WordPress. The concept makes sense to me.

  1. Install both Nginx and Apache
  2. Go to /etc/apache2/sites-available/000_default.conf and open in Nano.
  3. Change default file to point to port 8000, or some other port than 80.
  4. Go to /etc/nginx/sites-available/default and open in Nano.
  5. Change the server block
server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        root /var/www;
        index index.html index.php index.htm;

        # Make site accessible from http://localhost/
        server_name localhost;

        location / {
                try_files $uri $uri/ @backend;
        }

        location ~ \.php {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forward-For $remote_addr;
                proxy_set_header Host $host;
                proxy_pass http://127.0.0.1:8080;
        }

        location @backend {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forward-For $remote_addr;
                proxy_set_header Host $host;
                proxy_pass http://127.0.0.1:8080;
        }

   }

A Server Block defines a server_name and listen directives to bind to TCP sockets. In this case, the server_name is localhost. The listen directive is told to bind to port 80.

The root is the root of your web server. Both Nginx and Apache will share the web server root /var/www. This is important. I tried getting both Nginx and Apache to serve files from Nginx's default root, /usr/share/nginx/html, but that did not work. I'm not entirely sure it wasn't just a typo that made me fall back to /var/www, but when I did, the system started working. It may have been a permissions issue too.

The Location directive reads the requests coming from a browser, just the URI portion of the request--everything before the ?. The first one directs requests to use URI to find a file or a directory; otherwise, go to the proxy @backend. The location directive @backend, sends the requests via proxy_pass to localhost (127.0.0.1 port 8080), which is the Apache server. The location directive above @backend is case sensitive and uses a Regular Expression to filter the URI request string. Only those requests ending in .php are sent via proxy_pass to the Apache server.

proxy_set_header let's you to redefine or append the header that is passed to the proxy server. $remote_addr is $_SERVER['remote_addr'], a server variable containing the client address.

X-Forwarded-For is usually used by proxies to carry original Client IP through intermediary hops. I guess the same could be said for X-Real-IP. It's just used by proxies to carry original Client IP.



~ case-sensitive matching
~* case-insensitive matching


Friday, January 2, 2015

Setting Up Multiple Domains on Nginx

I moved two domains off my shared hosting server to my Digital Ocean account.

It's a three-step process:

  • Point the domains to new name servers
  • Add domains to DNS
  • Writing Nginx configuation files

Use the domain registrar's control panel to change the domain name server addresses. I pointed both domains to the Digital Ocean name servers.

Before creating new configuration files for Nginx, create directories and index.html files for each of the domains. The server needs something to serve and Nginx needs a path to the root of each server defined in a server block.

On Digital Ocean, there's a control panel for my Droplet that let's me associate a domain name with a server IP address. I add both of my domain names and point them at the IP address for my Droplet.

This is a server block:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /usr/share/nginx/html/myDomainName.com/public_html/;
        index index.html index.htm;

        server_name myDomainName.com www.myDomainName.com;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }
}

The first two lines tell Nginx which port to listen for request. The first is for IPv4 and the second is for IPv6.

Next, tell Nginx where to find the root of the web server. The path that follows points to the index.html file. the next line, index index.html index.htm, tells Nginx what file name to look for.

server_name is a parameter that accompanies a server request. Only if the server name matches myDomainName.com or www.myDomainName.com, Nginx looks in the root for an index.html file and returns it.

The location block inside the server block contains a try_files directive. This tells Nginx how to handle the situation if there's no index.html file at the root location. In this case, it tells Nginx to return a 404 error.

Notice that default_server is red and in bold. It's trying to say that only one server block can have the string default_server in the listen statement. I could configure twenty domains on my DO Droplet, but only one can have default_server in the listen statement.


Sources:
Nginx Documentation - Server Names
Multiple Nginx Server Blocks
Set up a Host Name on Digital Ocean Droplet