First logged into Ubuntu 16.04 server using
ssh -p [portNuumber] user-name@ipaddress/host
Open the ssh config
file to make changes
vi /etc/ssh/sshd_config
Uncomment the port 22 line, changed the ssh port number from 22 to something under 1024
# What ports, IPs and protocols we listen for
Port 123
restart the ssh service to apply changes
service ssh restart
Logged in again via SSH, now this time with the different port number [as the ssh port we changed in the above steps].
Added a new user to do ssh so that we don't allow root user for ssh.
adduser username # e.g. adduser your-sshable-user
Enter new UNIX password: 123InsecurePassword^
Retype new password: 123InsecurePassword^
Full Name []: your-sshable-user
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Added user to admin group
adduser your-sshable-user@ sudo
Disabled the root login in the ssh config file
vi /etc/ssh/sshd_config
PermitRootLogin no
Restarted ssh service
service ssh restart
Logged out and logged in again with the newly created ssh user to test it.
ssh -p 123 your-sshable-user@ipaddress/host
Enter password: 123InsecurePassword^
Generating RSA Keys
Logged out so I can create RSA private keys for SSH logins
The first step involves creating a set of RSA keys for use in authentication.
This should be done on the client.
To create your public and private SSH keys on the command-line:
https://help.ubuntu.com/community/SSH/OpenSSH/Keys
mkdir ~/.ssh # custom directory to store ssh keys
# https://chmodcommand.com/chmod-700/
# Chmod 700 sets permissions so that, user/owner can read, write and execute.
chmod 700 ~/.ssh
ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/[local-user]/.ssh/id_rsa): rsa_ssh_keys_custom_file
Enter passphrase (empty for no passphrase): 123InsecurePassword^
Enter same passphrase again: 123InsecurePassword^
Your identification has been saved in rsa_ssh_keys_custom_file.
Your public key has been saved in rsa_ssh_keys_custom_file.pub.
The key fingerprint is:
SHA256:AnBBBBBBBBBBBBBBBB user@local-ubuntu-server
The key's randomart image is:
+---[RSA 2048]----+
|.................|
+----[SHA256]-----+
Now its time to move the public key to the server
ssh-copy-id your-sshable-user@ipaddress/host -p 123
Logged into the server again so we can disable password authentication and allow only key.
ssh -p 123 your-sshable-user@ipaddress/host
Enter password: 123InsecurePassword^
sudo vi /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
Reloaded ssh config
sudo /etc/init.d/ssh reload
To remove ssh-server or ssh-client
sudo apt-get remove openssh-server
sudo apt-get remove openssh-client
sudo apt-get remove ssh
Installed firewall ufw
http://manpages.ubuntu.com/manpages/precise/en/man8/ufw.8.html
https://www.thefanclub.co.za/how-to/how-secure-ubuntu-1604-lts-server-part-1-basics
sudo apt-get install ufw
Added rules so that firewall allows SSH and HTTP ports
sudo ufw allow [ssh-port-no]/tcp #e.g ufw allow 123/tcp
sudo ufw allow http # this will add port 80
Enabled the firewall
sudo ufw enable
To check the status
sudo ufw status verbose
sudo ufw status numbered
Installed nginx
sudo apt-get update
sudo apt-get install nginx
Check nginx default config
sudo vi /etc/nginx/conf # open nginx config
Nginx configuration before making any changes
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
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 Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# 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;
##
# Virtual Host Configs
##
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;
# }
#}
Disable default server.
Failure to specify a proper server_name directive exposes your app to security vulnerabilities. Subdomain wildcard binding (for example, *.example.com) doesn't pose this security risk if you control the entire parent domain (as opposed to *.com, which is vulnerable). See rfc7230 section-5.4 for more information. https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1#configure-nginx
sudo vi /etc/nginx/sites-available/default
server {
listen 80 default_server;
listen [::]:80 default_server;
return 444;
}
Now we're ready to host websites under nginx.
The below config file we'll create for each website.
Since we're creating individual log directory for each website
we'll make sure the directory exists.
sudo mkdir /var/log/nginx/example.com # log directory
sudo mkdir /var/www/example.com # website directory
sudo vi /etc/nginx/sites-available/example.com.conf # nginx config file for example.com
server {
server_name example.com www.example.com;
listen 80;
listen [::]:80; # IPV6
index index.html;
# since website folder is at /var/www/
root /var/www/example.com;
access_log /var/log/nginx/example.com/access.log;
error_log /var/log/nginx/example.com/error.log;
location / {
try_files $uri $uri/ =404;
}
}
Then created a symbolic link aka shortcut inside sites-enabled. As that's the directory nginx looks up for websites.
sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
To test the domain let's create an html file
sudo vi /var/www/example.com/index.html
Content of the index.html file
<h1>example.com</h1>
Nginx needs to be reloaded to load the newly added sites config.
sudo nginx -t # checks if config files are valid/correct
sudo service nginx -s reload
At this stage the website should be browseable at http://example.com
If you observe the http response header of the website we'll find that
there is no security headers present and an unnecessary server: nginx/1.10.3 (Ubuntu)
present.
Now disable emitting nginx version
sudo vi /etc/nginx/nginx.conf
server_tokens off;
The above change still shows the http header server as Server: nginx
.
If you want to completely remove it then you can get the
source code of nginx and remove the server and recompile it.
Or install nginx-extras
.
apt-get install nginx-extras
That gave me a way to change http header Server value to something of my choice
more_set_headers 'server: something-else';
more_clear_headers Server;
Open the nginx config file and remove the deprecated/old TLS versions and
allow only TLS 1.1 & 1.2 and 1.3.
TLS 1.3
requires openSSL 1.1.1
or higher.
openssl version -a # check the version of openssl
ssl_protocols TLSv1.1 TLSv1.2;
Add all the common http headers in a file so that it can be shared among websites on the server
sudo vi /etc/nginx/security-headers.conf
x-content-type-options: nosniff
x-download-options: noopen
x-frame-options: DENY
x-permitted-cross-domain-policies: none
x-xss-protection: 1; mode=block
Include the above file contents in the example.com's config file
include /etc/nginx/security-headers.conf;
Install letsencrypt
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx
Generated SSL certificates for websites hosted on this server using LetsEncrypt
sudo certbot --nginx
SSL certificate generation wizard
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: example.com
2: www.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Certificate for example.com
(option 1
) selected.
Obtaining a new certificate
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/common
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
After selecting either options (1 or 2)
it will complete the installation of
the certificate and will make config changes accordingly.
The example.com.conf
file now looks like this:
server {
server_name example.com www.example.com;
listen 80;
listen [::]:80;
index index.html;
# since website folder is at /var/www/
root /var/www/example.com;
access_log /var/log/nginx/example.com/access.log;
error_log /var/log/nginx/example.com/error.log;
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl; # managed by Certbot
listen [::]:443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
If you've selected option 2 (Redirect), then make sure that the website always
renew certificate before it expires. Because LetsEncrypt creates a
301 permanent redirect
. Or you can change it to 302 redirect
.
example.com.config
now looks like;
server {
server_name example.com www.example.com;
listen 80;
listen [::]:80;
index index.html;
# since website folder is at /var/www directory
root /var/www/example.com;
access_log /var/log/nginx/example.com/access.log;
error_log /var/log/nginx/example.com/error.log;
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl; # managed by Certbot
listen [::]:443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
Remember one important thing here is the 404 status
for all non matching host name requests.
A request gets here when someone browses by your server ip address on ssl e.g. https://0.0.0.0:443
instead of host name https://example.com
.
server{
if($host = example.com){
return 301 https://$host$request_uri;
}
server_name example.com www.example.com;
listen 80;
return 404;
}
scp -r -P [ssh-port-no] /path/to/local/directory/ your-sshable-user@ipaddress/host:/path/to/remote/directory
#e.g.
scp -r -P 123 /var/serverData/ your-sshable-user@0.0.0.0:/home/your-sshable-user/
scp -r -P [ssh-port-no] your-sshable-user@ipaddress/host:/path/to/remote/directory/ /path/to/local/directory/
#e.g
scp -r -P 123 your-sshable-user@0.0.0.0:/var/www/logs /var/www/website-logs