Backend Coder Logo

Workflow: setting up a web server

Published: 19th Dec 2016

I have recently set up 2 new web servers on a Raspberry Pi and on a Digital Ocean Droplet. They both had similar setups using Linux, PHP and NGINX as the web server. Also, I host multiple websites on each box. This post is both educational and a reminder to myself about how I set the servers up.

Set up secure (SSH) terminal access

Using a Terminal emulator and connecting over a secure (SSH) link allows us to administer our server from any computer on our local network. So our server does not need a keyboard, mouse, and display. SSH works over port 22, so this port needs to be open on the server Firewall. And to connect from a remote location outside of the local network, we need to port-forward port 22 from our router to the server.

A user name and some form of authentication needs to be passed to the server. Password login is OK over your local network but for external login it's more secure to use key-based authentication.

Software to use for the Terminal emulator includes Putty and Mobaxterm. With these we can set up sessions for our connections where we specify the server IP address, user name, and password or private key file. We may generate a public/private key pair using a Tool of the Terminal emulator. The public key is placed in an authorized_keys file in the users .ssh folder.

How to set up MobaXterm to connect to a server.

After setting up key-based authentication you may disable password authentication.

Another thing to do is to set the server to have a static IP address. Then the router will always port forward to the correct place and you will not need to update the terminal session details.

Now we can do all of our server admin tasks from the command line in the terminal window. Also, MobaXterm gives us a file explorer window to drag and drop files to and from folders between our computer and the server after we set things up correctly for users and groups.

Set up the Firewall

In Linux we use IP Tables to configure the Firewall from the command line. What we want to do is only allow access of incoming connections to ports that we expect to be accessed i.e. 80 (HTTP), 443 (HTTPS/SSL), and 22 (SSH). All other ports will be blocked.  We have to be super careful to not block ourselves from SSH access otherwise the server will be unreachable, requiring direct access with a keyboard or restoration of a backup image of the disk.

For outgoing connections, we allow our apps to send traffic out from any port when a previously accepted connection was made to the app.

To check the current Firewall settings use the command:

sudo iptables -L -v --line-numbers

This displays the chains of rules for Incoming, Port forward, and Outgoing packets of data.

We only need to set up the Incoming rules for the INPUT table as follows:

sudo iptables -I INPUT 1 -i lo -j ACCEPT
sudo iptables -I INPUT 2 -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

The first rule is to accept local host traffic. The second rule is to ensure that SSH connectivity is accepted. Then rules for internet traffic are appended. Finally, there is a rule to allow established or related two-way traffic to be accepted.

The changes are applied immediately, but to make them persist after a reboot we need this command:

sudo dpkg-reconfigure iptables-persistent

Router settings

If you buy a hosting package, then you can ignore this section. If you are setting up a server in your home or business building then you will need to set up your router to port-forward external web page requests to your server. The ports of interest are: 80 for HTTP traffic, and 443 for HTTPS traffic.  Email is outside of the scope of this post. Also you need to forward port 22 if you want to admin your server from remote locations.

Your router needs to have any traffic arriving on ports 80 and 443 forwarded to the local area network IP address of your web server. Also, the server must be set up with a static IP address. Usually, computers on your network get assigned IP addresses by the router, but in this case, your server must tell the router that it requires a certain static IP address.

From the outside world, your network is addressed by a WAN (Wide Area Network IP address). This is  assigned by your ISP when your router is power-cycled or occasionally updated by the ISP when they do some kind of update. With a business package, you can probably pay to have a fixed IP address. Otherwise you have to implement dynamic DNS updating.

With dynamic DNS, a script running on your server detects changes to your WAN IP address and then updates the IP addresses of domains that point to your server. But this requires a script running on an external site to report your WAN IP address back to your server script as it probes the external site according to a schedule.

Your ISP (Internet Service Provider) must allow traffic through the www ports (via their Fire Wall), otherwise you cannot set up a home web server without upgrading to a business package. You can test if it's possible by running a simple web server on your home computer and pinging the IP address from another location. Ping on the LAN (Local Area Network) from another computer connected to the router to test that your test server is working. And ping from another building (phone a friend to do it) to test the WAN (Wide Area Network) connection.

Another factor to bear in mind is that ISPs tend to provide fast download speeds, but much slower upload speeds (most important for a web server). So you need to use an online speed test service to make sure that you are not wasting your time setting up a home web server.

Install PHP

You can read about the latest versions of PHP at PHP.net

To check the version of any currently installed version of PHP use this command: php -v

To install PHP 7 use this command with a list of the modules that you may require. Note that you may add more modules later.

apt-get install php7.0-{fpm,curl,zip}

This will install PHP 7 with the FastCgi module (fpm) which is recommended.

Install NGINX

The NGINX web server is considered to be better coded and better at handling multiple connections than Apache2.

NGINX uses files called Server Blocks to configure each website. The files are stored in the /etc/nginx/sites-available/ folder. And to activate a site, a symbolic link is added to the /etc/nginx/sites-enabled/ folder pointing to the Server Block for the website.

The server is restarted to activate any changes with: sudo service nginx restart

To install nginx we do: apt-get install nginx

Now look for the welcome page at 127.0.0.1 in a web browser.

Websites will be hosted in the /var/www/ folder. The owner and group should be set to www-data.

Also, make your user a member of this group. I usually put my website into a folder as follows: /var/www/mysite.com/public/

To set the ownership do:

sudo chown -R www-data:www-data /var/www

Add group write permissions with: sudo chmod -R g+w /var/www

A server block for an HTTPS site may look like this:

server {
	server_name .mysite.com;
	root /var/www/mysite.com/public;
	access_log /var/log/nginx/mysite.com.access.log;

	listen 443 ssl;

	ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;
	ssl_trusted_certificate /etc/letsencrypt/live/mysite.com/chain.pem;

	index index.php index.html;
	
    location / {
        try_files $uri $uri/ /index.php?route=$uri;
    }

	 # image file and .html file accesses aren't logged and expires header is set to maximum age
	 location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
		access_log off;
		expires max;
	}
	
	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
		fastcgi_pass unix:/run/php/php7.0-fpm.sock;
	}

	location ~ /\.ht {
		deny all;
	}
}

This is saved to: /etc/nginx/sites-available/mysite.com and a symbolic link added with:

sudo ln -s /etc/nginx/sites-available/mysite.com /etc/nginx/sites-enabled/mysite.com

In the nginx configuration file there is also a place to add server blocks. This is useful for detecting access to websites on port 80 (HTTP) that should be redirected to port 443 (HTTPS). The first server block that is matched to a domain name is used so if a site is on port 80 then it will still work. Edit the file with: sudo nano /etc/nginx/nginx.conf

Make the Virtual Host Configs section look like this:


        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
        server {
                listen 80 default_server;
                listen [::]:80 default_server;
                server_name _;
		access_log off;
                return 301 https://$host$request_uri;
        }

You can see that the sites-enabled server blocks will be processed before our server block here. This server block listens on port 80 and does a 301 (permanently moved) redirect to the https URL of the website if there was no server block found for the http url of the website.

Then: sudo service nginx restart

Web browsers should remember this redirect in their cache so they will load the correct URL on the next visit.

This was a quick overview of NGINX, there are more detailed guidelines here: Getting Started

Good luck setting up your server!