Super-fast Secure VPS Configuration Tutorial for Nextpost

March 6, 2021| SocialMediaTools

This is the ultimate and must-known digital tutorial about web-server (VPS/VDS) configuration for Nextpost based on my 6 years of experience in Web Development.

Here I’ve documented the steps I use to configure a new server instance.

Сontent

Introduction

I think backend is the hardest side of Web Development.

Since I started my experience I spent a lot of time to find and understand which parameters are best, why we set these values and not any other.

This digital guide is the quintessence of all the information that I found on my way of Web Development.

Let’s get started.

Step 1: Software for Web Development

For the best experience I suggest you download and install these programs to you Mac/Windows laptop or PC:

  • Visual Studio Code – for web programming, profiling and code editing.
  • FTP Manager:
    • I prefer to use Transmit 5 on my Mac – simple, fast and cool.
    • If you are Windows/Mac user you can download FileZilla, best of the best for everyone.

Step 2: Create and setup your Droplet/VDS in DigitalOcean

The first question that you can have: Which cloud VPS should I choose?.

And the golden answer is: Best of the best cloud VPS provider in the whole world is DigitalOcean. No additional words are needed. Just trust me and follow this guide.

If you are using another hosting provider, configure your droplet with the following settings:

  • Ubuntu 18.04 (LTS)
  • Min. RAM: 1 GB

2.1. DigitalOcean Droplet Creation

Go to your DigitalOcean Dashboard and create a New Project. Name him as you want, in my example, it’s Eye of God.

After that start the droplet creation process.

In the tab, Distribution click on Ubuntu 18.04.3 (LTS) x64 and select a needed plan. You can start with a minimum plan and upgrade your droplet to a large one in the future. At the moment it’s not so necessary.

Choose the nearest region to you. For me, it’s Frankfurt, Germany. You can use this speed test tool provided by DigitalOcean to compare droplet downloads/upload speeds from your current location.

In section Additional options check following checkboxes:

  • Private Networking
  • IPv6
  • Monitoring

The most important step is Authentication. Here we should add laptop/PC SSH keys from all our devices from which we want to have access to our web server.

Follow these instructions to create or add SSH keys on Linux, MacOS & Windows. Windows users without OpenSSH can install and use PuTTY instead.

Create a new key pair, if needed

If you already generated an SSH key for your device go to step Add the public key.

Open a terminal and run the following command:

ssh-keygen

You will be prompted to save and name the key.

Generating public/private rsa key pair. Enter file in which to save the key (/Users/USER/.ssh/id_rsa):

Next, you will be asked to create and confirm a passphrase for the key (highly recommended):

Enter passphrase (empty for no passphrase):<br>Enter same passphrase again:

This will generate two files, by default called id_rsa and id_rsa.pub. Next, add this public key.

Add the public key

Copy and paste the contents of the .pub.pub file, typically id_rsa.pub, into the SSH key content field on the left.

cat ~/.ssh/id_rsa.pub

For more detailed guidance, see How to Add SSH Keys to Droplets

Add your unique SSH key to DigitalOcean.

Add all needed devices and mark SSh keys checkboxes, you can also choose custom hostname and add tags. Finally, choose a project, that we created recently.

I strongly recommend you enable Backups. This will be a lifesaver option if your website somehow will be hacked or broken in unknown reasons. 

Recently I have the experience when hackers in an unknown way got access to the webserver and deleted a website with the cost equal to 30k USD. Backup saved my life from unwanted recovery work.

Wait a few minutes while your droplet configurated.

After that go to the droplet section and copy your server IP.

2.2. Server Configuration

When you first create a new Ubuntu 18.04 server, there are a few configuration steps that you should take early on as part of the basic setup.

This will increase the security and usability of your server and will give you a solid foundation for subsequent actions.

Follow this tutorial and make a initial server setup Initial Server Setup with Ubuntu 18.04.

When you open the page with Nano Editor you can see keyboard shortcuts, where ^ symbol is CTRL (control) key. For save changes and exit from nano editor just type CTRL+X in one moment and say yes in prompt.

After that I save changes with CTRL+X command and reload SSH:

sudo systemctl reload sshd

Log out from a web server and login again with this new command where:

  • your_server_ip – your own web server (droplet) IP address.
exit
ssh [email protected]_server_ip

Step 3: Connect your domain with web-server

At this point, it’s also a good idea to set up your domain name to point to your server.

Once you’ve set it up, it can take up to a couple of days for the change to take effect, but in practice, it usually only takes a few minutes to a couple of hours.

Log in to the site where you registered your domain name and change the nameservers to point to ns1.digitalocean.com,  ns2.digitalocean.com, and ns3.digitalocean.com.

After you do that, head over to your DigitalOcean account and go to Networking > Domains.

In the form to “Add a Domain” enter your domain name and then select the droplet, you created in Step 2.

I typically set up my domains to route email through Gmail.

Here, you can find tutorial to set up your DNS to use GMail’s servers.

Add 2 A-records for connecting your domain with the webserver.

Finally, it’s should look like that.

Step 4: Install NGINX

Let’s install a custom version of NGINX. From the command line.

Every command you should type from a new line and press Enter.

sudo apt-get update
sudo apt-get install nginx
sudo ufw allow 'Nginx Full'
sudo ufw enable

Step 5: Install and Configure MariaDB

MariaDB is a drop-in replacement for MySQL. You can read about why people think it’s better, but I’m mostly convinced by the performance arguments. The MariaDB website has a convenient tool for configuring the correct repositories in your Ubuntu distro. Using the tool, I came up with the following steps for installing the DB:

sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.2/ubuntu xenial main'
sudo apt-get update
sudo apt-get install mariadb-server

Go next and run this command:

sudo mysql_secure_installation

After that press Enter and y to create a new root password. Make sure you provide a good secure password that is different from the password you used for your user account.

Since you’ve already set up a secure password for your root user, you can safely answer “no” to the question asking you to create a new root password. Answer “Yes” to all of the other questions. 

Now we can set up a separate MariaDB account and database for our Nextpost instance. At the command prompt type the following:

sudo mysql -u root -p

Type in your password when prompted.

This will open up a MariaDB shell session. Everything you type here is treated as an SQL query, so make sure you end every line with a semicolon! This is very easy to forget. Here are the commands you need to type in to create a new database, user, and assign privileges to that user:

CREATE DATABASE nextpost_db DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
GRANT ALL ON nextpost_db.* TO 'nextpost_db_user'@'localhost' IDENTIFIED BY 'securepassword';
FLUSH PRIVILEGES;
quit

Note that although it’s customary to use ALL CAPS to write SQL statements like this, it is not strictly necessary.

Also, where I’ve used “nextpost_db” and “nextpost_db_user” feel free to use your own database and user names, and as securepassword use own secure password value.

Finally, it is recommended that you create a MariaDB sources.list file. This file will make sure that when your server periodically looks for updates, it will also check the MariaDB repository to keep it up to date.

Create the file and open it for editing by typing the following at the command prompt:

sudo nano /etc/apt/sources.list.d/MariaDB.list

Copy and paste the following code into that file:

# MariaDB 10.2 repository list - created 2019-10-1 18:00 UTC
# http://downloads.mariadb.org/mariadb/repositories/
deb [arch=amd64,i386] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.2/ubuntu xenial main
deb-src http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.2/ubuntu xenial main

Save and close the file by typing CTRL + X.

Check how much free RAM there is on the server with command:

free -hm

Example:

Set MySQL buffer pool size in /etc/my.cnf less than amount of free RAM.

In our example, we have 122M free, and for innodb_buffer_pool_size we will set 100M. Your value will be different but should be less than the amount of free RAM.

For our example:

innodb_buffer_pool_size=100M

Restart MySQL service with :

service mariadb restart

Step 6: Install and Configure PHP7-FPM

One of the cool things about Ubuntu 20.04 is that it’s default PHP packages now default to version 7!

Installing PHP is as simple as typing the following:

sudo apt-get install -y zip unzip php-fpm php-mysql php-xml php-gd php-mbstring php-zip php-curl

Note that this also installs the MySQL, XML, Curl and GD packages so that Nextpost can interact with the database and also automatically crop and resize images. It also installs zip/unzip.

Now run this command in the console:

php -v

From that line, we can find the current PHP version of our server. This should be a 7.4.

And now we can run this command to edit php.ini settings:

sudo nano /etc/php/7.4/fpm/php.ini

Also, the easiest way to edit files of our server is to use File Manager and connect to the server via FTP. Software for this you can find in Step 1.

SFTP connection with the webserver in Transmit 5.

When you use FTP Manager it’s really useful to open the file in Microsoft Visual Studio Code and edit him directly. All changes will be applied to the server file after we save changes in the Visual Studio Code.

Open /etc/php/7.4/fpm/php.ini (your PHP version can be higher 7.3 or 7.4) and change the default values to these:

max_execution_time = 60
memory_limit = 512M
display_errors = On
post_max_size = 100M 
upload_max_filesize = 100M
default_socket_timeout = 300

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=60

After that save changes in the file.

Open the next one /etc/php/7.4/fpm/pool.d/www.conf.

Set pm to dynamic:

pm = dynamic

Configure dynamic pool

For the main application server, due to obvious advantages, they often choose a dynamic pool. Its operation is described by the following settings:

  • pm.max_children – the maximum number of child processes
  • pm.start_servers – the number of processes at startup
  • pm.min_spare_servers – the minimum number of processes waiting for a connection (requests for processing)
  • pm.max_spare_servers – the maximum number of processes waiting for a connection (requests for processing)

In order to correctly set these values, you must consider:

  • how much memory does the child process consume on average
  • amount of RAM available

To find out the average memory value per php-fpm process on an already running application, use the scheduler:

ps -ylC php-fpm --sort:rss

In my case, I use Nextpost + Hyperloop Masslooking module and one process takes ~50Mb.

The total / available / used memory can be viewed using free:

# free -m
              total        used        free      ... 
Mem:           1993         181        1574        

My server has 2GB of RAM. Next, we take the formula for calculating pm.max_children (source) as a basis, and perform an example calculation:

Total Max Processes = (Total Ram - (Used Ram + Buffer)) / (Memory per php process)

Total RAM: 2GB
RAM used: 200MB
Security buffer: 400MB
Memory for one child php-fpm process (average): 30MB

The maximum possible number of processes = (2000 - (200 + 400)) / 50 = 28
Even number: 28 rounded down to 20
pm.max_children = 20

pm.min_spare_servers = Total RAM = 2
pm.max_spare_servers = 2 * Total RAM = 4

pm.start_servers = min_spare_servers + (max_spare_servers - min_spare_servers) / 2 = 3

pm.max_requests = 0

For example, I have a server with 4GB and use the following settings in /etc/php/7.4/fpm/pool.d/www.conf:

pm = dynamic
pm.max_children = 60
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.start_servers = 6
pm.max_requests = 0

To get PHP to load the changes you need to restart it by typing:

sudo service php7.4-fpm restart

Step 7: How To Install and Secure phpMyAdmin on Ubuntu 20.04

For easy database management, I’m using phpMyAdmin.

Here you can find a tutorial about how to install phpMyAdmin on Ubuntu.

Then set the appropriate permissions for the phpMyAdmin root directory to prevent access errors.

sudo chmod 775 -R /usr/share/phpmyadmin/
sudo chown -R www-data:www-data /usr/share/phpmyadmin/

If the login with the root username fails (because it requires sudo starting with MySQL 5.7), you may need to create a new administrator account in order to access the mariadb shell using the root account from the terminal.

sudo mysql -u root -p
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'securepassword';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Now you can use the new credentials to enter in phpMyAdmin to manage the MySQL databases.

Useful links:

  • Error – count(): Parameter must be an array or an object that implements Countable – FIXED, the solution is here.

Step 8: Set up free SSL Certificates with LetsEncrypt with an auto-renew cronjob

In the next step, we’re going to add an SSL certificate to our site and then configure NGINX to use it. I recommend that you read DigitalOcean’s entire tutorial on securing NGINX on Ubuntu 20.04 with LetsEncrypt, but I’ll provide just the steps you need here.

First, install LetsEncrypt:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

Next, we’ll install our certs using:

sudo certbot --nginx certonly -d yoursite.com

If all will be ok you will see something like this:

Repeat process for www.yoursite.com

sudo certbot --nginx certonly -d www.yoursite.com

[OPTIONAL] If you are running Nextpost on the subdomain you should obtain certificates for subdomain:

  • subdomain – your custom unique name

First of all, add DNS A-records for the subdomain in DNS management.

  • subdomain and server-IP
  • www.subdomain and server-IP

After that obtain certificates.

sudo certbot --nginx certonly -d subdomain.yoursite.com
sudo certbot --nginx certonly -d www.subdomain.yoursite.com

Next, we’ll edit the configuration snippet for NGINX that was created by Certbot and which will contain all of our SSL parameters.

Open the file as follows:

sudo nano /etc/letsencrypt/options-ssl-nginx.conf

Edit the file so that it looks like the one below. The top six or seven lines should have been created automatically for you by Certbot, and the ones below add the extra parameters we’ll need to take advantage of our heightened security profile:

# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.

ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1440m;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-R$

# MANUALLY ADD THESE
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;

Save and exit this file.

It is important to note that SSL certificates from LetsEncrypt expire every 90 days. In order that you don’t have to log into your server every 3 months to renew your certs, we’re going to set up a CRON job to auto renew them.

From the command line:

sudo crontab -e

Type just Enter in prompt.

Remove everything in the file and add the following lines:

30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log
35 2 * * 1 /bin/systemctl reload nginx

This will update the LetsEncrypt client and then attempt to renew and load your certs (if necessary) every Monday.

In case you’d like to test to make sure the automated renewal will work, you can use the following command to do a dry run:

sudo certbot renew --dry-run

Step 9: Tell NGINX to use PHP7-FPM. NGINX config for Nextpost. Securing and Optimizing.

Open up the configuration file with File Manager for your default site for NGINX:

/etc/nginx/sites-available/default

Edit the file so that it looks like this but change yoursite.com and www.yoursite.com to reflect the URL for your website.

This NGINX configuration file already optimized for use with any Nextpost installation.

If you are running Nextpost on subdomain change yoursite.com everywhere to subdomain.yoursite.com.

Your PHP version can be higher 7.3 or 7.4:

  • fastcgi_pass unix:/run/php/php7.3-fpm.sock;
  • fastcgi_pass unix:/run/php/php7.4-fpm.sock;
server {
    listen 80;
    listen [::]:80;

    # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
    return 301 https://$host$request_uri;
}

server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/yoursite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/yoursite.com/privkey.pem; # managed by Certbot
	ssl_trusted_certificate /etc/letsencrypt/live/yoursite.com/chain.pem; 
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

	client_max_body_size 128M;
	root /var/www/html;
	index index.php index.html index.htm;	

	server_name yoursite.com;

	location / {
		try_files $uri $uri/ /index.php?$args;
	}

	location ~ \.css {
    		add_header  Content-Type    text/css;
	}
	
	location ~ \.js {
    		add_header  Content-Type    application/x-javascript;
	}

	location ~* \.(eot|otf|ttf|woff|woff2)$ {
    		add_header Access-Control-Allow-Origin *;
	}

	location /phpmyadmin {
    		alias /usr/share/phpmyadmin;
    		index index.php index.html index.htm;

    		location ~ ^/phpmyadmin/(.+\.php)$ {
        		alias /usr/share/phpmyadmin/$1;
        		fastcgi_split_path_info ^(.+\.php)(/.+)$;

        		fastcgi_index index.php;
        		fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin/$1;
        		fastcgi_pass unix:/run/php/php7.2-fpm.sock;
				include fastcgi_params;
				fastcgi_send_timeout 300;
				fastcgi_read_timeout 300;
				fastcgi_buffer_size 128k;
                fastcgi_buffers 4 256k;
    		}

    		location ~* ^/phpmyadmin/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
        		alias /usr/share/phpmyadmin/$1;
    		}
	}	

	location ~ \.php$ {
    	include snippets/fastcgi-php.conf;
    	fastcgi_pass unix:/run/php/php7.2-fpm.sock;
		include fastcgi_params;
		fastcgi_send_timeout 300;
		fastcgi_read_timeout 300;
		fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
  	}

  	location ~ /\.ht {
    	deny all;
  	}

}

server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;
	server_name www.yoursite.com;
	return 301 https://www.yoursite.com$request_uri;

    ssl_certificate /etc/letsencrypt/live/www.yoursite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/www.yoursite.com/privkey.pem; # managed by Certbot
	ssl_trusted_certificate /etc/letsencrypt/live/www.yoursite.com/chain.pem; # managed by Certbot
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot	
}

After that save changes in the config file and restart web server using these commands:

sudo service nginx restart
sudo service php7.4-fpm restart
sudo service mysqld restart
sudo service cron reload

And also change folder permissions from root to www-data, if you are logged in in FTP Manager as the root user.

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

For a test that all working well create a file index.php in /var/www/html with this content:

<?php
   phpinfo();
?>

Now go to the browser and open page with your domain. You will see information about your PHP, that we installed before.

Delete this file index.php file.

Step 10: Install FFmpeg for Nextpost

Q: How to post videos in Nextpost? Install ffmpeg?

A: For install ffmpeg just run this command in Terminal, add binary path to config and enable Video checkpoints in Packages and User Settings:

git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
apt install ffmpeg

That’s all.

Q: How do I know the path of ffmpeg?

Use these commands:

whereis ffmpeg
whereis ffprobe

Step 11: Nextpost Installation

Place all Nextpost script files in /var/www/html/ folder.

Now you can start standard Nextpost installation. All steps explained here.

Step 12: Troubleshooting.

12.1. Hyperloop Masslooking module. Task status all time is “Scheduled” and don’t changed to “Active”.

Please check is cronjob works in all you modules correctly. If cron not working correctly in one of modules, it’s can break all cronjob system.

/var/log/ – here you can find server logs

That’s all, thank you!

Now clean browser cache and take a look at your changes. For example I attached screenshot from Chrome.

Categories: Uncategorized
Support