Below is my guide on setting up a Vultr VM and configuring it with a static IP, NGINX, MySQL, PHP and an SSL certificate.
I have blogged about setting up Centos and Ubuntu server on Digital Ocean before. Digital Ocean does not have data centres in Australia and this kills scalability. AWS is good but 4x the price of Vultr. I have also blogged about setting up and AWS server here. I tried to check out Alibaba Cloud but the verification process was broken so I decided to check our Vultr.
Update (June 2018): I don’t use Vultr anymore, I moved my domain to UpCloud (they are that awesome). Use this link to signup and get $25 free credit. Read the steps I took to move my domain to UpCloud here.
UpCloud is way faster.
Buy a domain name from Namecheap here.
Setting up a Vultr Server
1) Go to http://www.vultr.com/?ref=7192231 and create your own server today.
2) Create an account at Vultr.
3) Add a Credit Card
4) Verify your email address, Check https://my.vultr.com/promo/ for promos.
5) Create your first instance (for me it was an Ubuntu 16.04 x64 Server, 2 CPU, 4Gb RAM, 60Gb SSD, 3,000MB Transfer server in Sydney for $20 a month). I enabled IPV6, Private Networking, and Sydney as the server location. Digital Ocean would only have offered 2GB ram and 40GB SSD at this price. AWS would have charged $80/w.
2 Cores and 4GB ram is what I am after (I will use it for NGINX, MySQL, PHP, MongoDB, OpCache and Redis etc).
6) I followed this guide and generated an SSH key and added it to Vultr. I generated a local SSH key and added it to Vultr
snip
7) I was a bit confused if the UI adding the SSH key to the in progress deploy server screen (the SSH key was added but was not highlighted so I recreated the server to deploy and the SSH key now appears).
Now time to deploy the server.
Deploying now.
My Vultr server is now deployed.
I connected to it with my SSH program on my Mac.
Now it is time to redirect my domain (purchased through Namecheap) to the new Vultr server IP.
DNS: @ A Name record at Namecheap
Update: I forgot to add an A Name for www.
DNS: Vultr (added the Same @ and www A Name records (fyi “@” was replaced with “”)).
I waited 60 minutes and DNS propagation happened. I used the site https://www.whatsmydns.net to see where the DNS replication was and I was receiving an error.
Setting the Serves Time, and Timezone (Ubuntu)
I checked the time on zone server but it was wrong (20 hours behind)
I manually set the timezone to Sydney Australia.
I installed the NTP time syncing service
I configured the NTP service to use Australian servers (read this guide).
I checked the time after restarting NTP.
The time is correct 🙂
Installing NGINX Web Server Webserver (Ubuntu)
Installing NodeJS (Ubuntu)
Installing MySQL (Ubuntu)
Install PHP 7.x and PHP7.0-FPM (Ubuntu)
php.ini
Restart PHP
Now install misc helper modules into php 7 (thanks to this guide)
Initial NGINX Configuring – Pre SSL and Security (Ubuntu)
Here is a good guide on setting up NGINX for performance.
Edit the NGINX configuration
File Contents: /etc/nginx/nginx.conf
File Contents: /etc/nginx/sites-available/default
I talked to Dmitriy Kovtun (SSL CS) on the Namecheap Chat to resolve a privacy error (I stuffed up and I am getting the error “Your connection is not private” and “NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN”).
SSL checker says everything is fine.
I checked the certificate strength with SSL Labs (OK).
Test and Reload NGINX (Ubuntu)
Create a test PHP file
It Works.
Install Utils (Ubuntu)
Install an interactive folder size program
Install a better disk check utility
Display startup processes
Install JSON helper
Increase the console history
I rebooted to see if PHP started up.
OpenSSL Info (Ubuntu)
Read about updating OpenSSL here.
Update Ubuntu
Vultr Firewall
I configured the server firewall at Vultr and ensured it was setup by clicking my server, then settings then firewall.
I then checked open ports with https://mxtoolbox.com/SuperTool.aspx
Assign a Domain (Vultr)
I assigned a domain with my VM at https://my.vultr.com/dns/add/
Charts
I reviewed the server information at Vultr (nice).
Static IP’s
You should also setup a static IP in /etc/network/interfaces as mentioned in the settings for your server https://my.vultr.com/subs/netconfig/?SUBID=XXXXXX
Backup your existing Ubuntu 16.04 DHCP Network Configuratiion
I would recommend you log a Vultr support ticket and get the right IPV4/IPV6 details to paste into /etc/network/interfaces while you can access your IP.
It is near impossible to configure the static IP when the server is refusing a DHCP IP address (happened top me after 2 months).
If you don’t have time to setup a static IP you can roll with Auto DHCP IP assignment and when your server fails to get and IP you can manually run the following command (changing the network adapter too your network adapter) from the web root console.
I logged a ticket for each of my other servers to get thew contents or /etc/network/interfaces
Support Ticket Contents:
Install an FTP Server (Ubuntu)
I decided on pureftp-d based on this advice. I did try vsftpd but it failed. I used this guide to setup FTP and a user.
I used this guide to setup an FTP and a user. I was able to login via FTP but decided to setup C9 instead. I stopped the FTP service.
Add an SSL certificate (Reissue existing SSL cert at NameCheap)
I had a chat with Konstantin Detinich (SSL CS) on Namecheap’s chat and he helped me through reissuing my certificate.
I have a three-year certificate so I reissued it. I will follow the Namecheap reissue guide here.
I recreated certificates
I posted the CSR into Name Cheap Reissue Certificate Form.
Tip: Make sure your certificate is using the same name and the old certificate.
I continued the Namecheap prompts and specified HTTP domain control verification.
Namecheap Output: When you submit your info for this step, the activation process will begin and your SSL certificate will be available from your Domain List. To finalize the activation, you’ll need to complete the Domain Control Validation process. Please follow the instructions below.
Now I will wait for the verification instructions.
Update: I waited a few hours and the instructions never came so I logged in to the NameCheap portal and downloaded the HTTP domain verification file. and uploaded it to my domain.
I forgot to add the text file to the NGINX allowed files in files list.
I added the following file: /etc/nginx/sites-available/default
I reloaded and restarted NGINX
The file now loaded over port 80. I then checked Namecheap chat (Alexandra Belyaninova) to speed up the HTTP Domain verification and they said the text file needs to be placed in /.well-known/pki-validation/ folder (not specified in the earlier steps).
The certificate reissue was all approved and available for download.
I uploaded all files related to the ssl cert to /etc/nginx/ssl/ and read my guide here to refresh myself on what is next.
I ran this command in the folder /etc/nginx/ssl/ to generate a DH prime rather than downloading a nice new one from here.
This namecheap guide will tell you how to activate a new certificate and how to generate a CSR file. Note: The guide to the left will generate a 2048 bit key and this will cap you SSL certificates security to a B at http://www.sslabs.com/ssltest so I recommend you generate an 4096 bit csr key and 4096 bit Diffie Hellmann key.
I used https://certificatechain.io/ to generate a valid certificate chain.
My SSL /etc/nginx/ssl/sites-available/default config
My /etc/nginx/nginx.conf Config
# https://github.com/denji/nginx-tuning user www-data; worker_processes auto; worker_cpu_affinity auto; pid /run/nginx.pid; worker_rlimit_nofile 100000; error_log /var/log/nginx/nginxcriterror.log crit; events { worker_connections 4000; use epoll; multi_accept on; } http { limit_conn conn_limit_per_ip 10; limit_req zone=req_limit_per_ip burst=10 nodelay; # copies data between one FD and other from within the kernel faster then read() + write() sendfile on; # send headers in one peace, its better then sending them one by one tcp_nopush on; # don't buffer data sent, good for small data bursts in real time tcp_nodelay on; # reduce the data that needs to be sent over network -- for testing environment gzip on; gzip_min_length 10240; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/json application/xml; gzip_disable msie6; # allow the server to close connection on non responding client, this will free up memory reset_timedout_connection on; # if client stop responding, free up memory -- default 60 send_timeout 2; # server will close connection after this time -- default 75 keepalive_timeout 30; # number of requests client can make over keep-alive -- for testing environment keepalive_requests 100000; # Security server_tokens off; # limit the number of connections per single IP limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m; # limit the number of requests for a given session limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s; # if the request body size is more than the buffer size, then the entire (or partial) request body is written into a temporary file client_body_buffer_size 128k; # headerbuffer size for the request header from client -- for testing environment client_header_buffer_size 3m; # to boost I/O on HDD we can disable access logs access_log off; # cache informations about FDs, frequently accessed files # can boost performance, but you need to test those values open_file_cache max=200000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; # maximum number and size of buffers for large headers to read from client request large_client_header_buffers 4 256k; # read timeout for the request body from client -- for testing environment client_body_timeout 3m; # how long to wait for the client to send a request header -- for testing environment client_header_timeout 3m; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # 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/javascript text/xml application/xml application/xml+rss text/javascript; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } #mail { # # See sample authentication script at: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript # # # auth_http localhost/auth.php; # # pop3_capabilities "TOP" "USER"; # # imap_capabilities "IMAP4rev1" "UIDPLUS"; # # server { # listen localhost:110; # protocol pop3; # proxy on; # } # # server { # listen localhost:143; # protocol imap; # proxy on; # } #}
Namecheap support checked my certificate with https://decoder.link/sslchecker/ (no errors). Other SSL checkers are https://certlogik.com/ssl-checker/ and https://sslanalyzer.comodoca.com/
I was given a new certificate to try by Namecheap.
Namecheap Chat (Dmitriy) also recommended I clear my google cache as they did not see errors on their side (this worked).
SSL Security
Read my past guide on adding SSL to a Digital Ocean server.
I am checking my site with https://www.ssllabs.com/ssltest/ (OK).
My site came up clean with shodan.io
Securing Ubuntu in the Cloud
Read my guide here.
OpenSSL Version
I checked the OpenSLL version to see if it was up to date
Yep, all up to date https://www.openssl.org/
I will check often.
Install MySQL GUI
Installed the Adminer MySQL GUI tool (uploaded)
Don’t forget to check your servers IP with www.shodan.io to ensure there are no back doors.
I had to increase PHP’supload_max_filesize file size temporarily to allow me to restore a database backup. I edited the php file in /etc/php/7.0/fmp/php.ini and then reload php
I used Adminer to restore a database.
Support
I found the email support to Vultr was great, I had an email reply in minutes. The Namecheap chat was awesome too. I did have an unplanned reboot on a Vultr node that one of my servers were on (let’s hope the server survives).
View the Vultr service status page is located here.
Conclusion
I now have a secure server with MySQL and other web resources ready to go. I will not add some remote monitoring and restore a website along with NodeJS and MongoDB.
Definitely, give Vulrt go (they even have data centers in Sydney). Signup with this link http://www.vultr.com/?ref=7192231
Namecheap is great for certificates and support.
Vultr API
Vultr has a great API that you can use to automate status pages or obtain information about your VM instances.
API Location: https://www.vultr.com/api/
First, you will need to activate API access and allow your IP addresses (IPV4 and IPV6) in Vultr. At first, I only allowed IPV4 addresses but it looks as if Vultr use IPV6 internally so add your IPV6 IP (if you are hitting the IP form, a Vultr server). Beware that the return JSON from the https://api.vultr.com/v1/server/list API has URLs (and tokens) to your virtual console and root passwords so ensure your API key is secured.
Here is some working PHP code to query the API
Your server will need to curl installed and you will need to enable URL opening in your php.ini file.
Once you have curl (and the API) working via PHP, this code will return data from the API for a nominated server (replace ‘123456’ with the id from your server at https://my.vultr.com/).
A raw packet looks like this from https://api.vultr.com/v1/server/list
I recommend the Paw software for any API testing locally on OSX.
Bonus: Converting Vultr Network totals from the Vultr API with PHP
Add the following as a global PHP function in your PHP file. Found the number formatting solution here.
<?php // Found at https://stackoverflow.com/questions/2510434/format-bytes-to-kilobytes-megabytes-gigabytes function swissConverter($value, $format = true, $precision = 2) { // Below converts value into bytes depending on input (specify mb, for // example) $bytes = preg_replace_callback('/^\s*(\d+)\s*(?:([kmgt]?)b?)?\s*$/i', function ($m) { switch (strtolower($m[2])) { case 't': $m[1] *= 1024; case 'g': $m[1] *= 1024; case 'm': $m[1] *= 1024; case 'k': $m[1] *= 1024; } return $m[1]; }, $value); if(is_numeric($bytes)) { if($format === true) { //Below converts bytes into proper formatting (human readable //basically) $base = log($bytes, 1024); $suffixes = array('', 'KB', 'MB', 'GB', 'TB'); return round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)]; } else { return $bytes; } } else { return NULL; //Change to prefered response } } ?>
Now you can query the https://api.vultr.com/v1/server/bandwidth?SUBID=123456 API and get bandwidth information related to your server (replace 123456 with your servers ID).
<h4>Network Stats:</h4><br /> <?php $ch = curl_init(); $headers = [ 'API-Key: removed' ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Change 123456 to your server ID curl_setopt($ch, CURLOPT_URL, 'https://api.vultr.com/v1/server/bandwidth?SUBID=123456'); $server_output = curl_exec ($ch); curl_close ($ch); //print $server_output ; curl_close($ch); $array = json_decode($server_output, true); //Get 123456 Incoming Bytes Yesterday $vultr123456_imcoming00ib = $array['incoming_bytes'][0][1]; echo " Incoming Data Total Day Before Yesterday: <strong>" . swissConverter($vultr123456_imcoming00ib, true) . "</strong><br/>"; //Get 123456 Incoming Bytes Yesterday $vultr123456_imcoming00ib = $array['incoming_bytes'][1][1]; echo " Incoming Data Total Yesterday: <strong>" . swissConverter($vultr123456_imcoming00ib, true) . "</strong><br/>"; //Get 123456 Incoming Bytes Today $vultr123456_imcoming00ib = $array['incoming_bytes'][2][1]; echo " Incoming Data Total Today: <strong>" . swissConverter($vultr123456_imcoming00ib, true) . "</strong><br/><br/>"; //Get 123456 Outgoing Bytes Day Before Yesterday $vultr123456_imcoming10ob = $array['outgoing_bytes'][0][1]; echo " Outgoing Data Total Yesterday: <strong>" . swissConverter($vultr123456_imcoming10ob, true) . "</strong><br/>"; //Get 123456 Outgoing Bytes Yesterday $vultr123456_imcoming10ob = $array['outgoing_bytes'][1][1]; echo " Outgoing Data Total Yesterday: <strong>" . swissConverter($vultr123456_imcoming10ob, true) . "</strong><br/>"; //Get 123456 Outgoing Bytes Today $vultr123456_imcoming00ob = $array['outgoing_bytes'][2][1]; echo " Outgoing Data Total Today: <strong>" . swissConverter($vultr123456_imcoming00ob, true) . "</strong><br/>"; echo "<br />"; ?>
Bonus: Pinging a Vultr server from the Vultr API with PHP’s fsockopen function
Paste the ping function globally
<?php function pingfsockopen($host,$port=443,$timeout=3) { $fsock = fsockopen($host, $port, $errno, $errstr, $timeout); if ( ! $fsock ) { return FALSE; } else { return TRUE; } } ?>
Now you can grab the servers IP from https://api.vultr.com/v1/server/list and then ping it (on SSL port 443).
//Get Server 123456 IP $vultr_mainip = $array['123456']['main_ip']; $up = pingfsockopen($vultr_mainip); if( $up ) { echo " Server is UP.<br />"; } else { echo " Server is DOWN<br />"; }
Setup Google DNS
Add line
dns-nameservers 8.8.8.8 8.8.4.4
What have I missed?
Read my blog post on Securing an Ubuntu VM with a free LetsEncrypt SSL certificate in 1 Minute.
Read my blog post on securing your Ubuntu server in the cloud.
Read my blog post on running an Ubuntu system scan with Lynis.
Donate and make this blog better
Ask a question or recommend an article
[contact-form-7 id=”30″ title=”Ask a Question”]
v1.993 added log info