# Install server
In this guide we will create a secure setup of a new Ubuntu (opens new window) server with Apache and Docker. This will be our base setup where we will install SenSeeAct later. There are of course many possible server configurations and you may already have a running Ubuntu server and web server. So chances are that you cannot follow this guide step by step and you might even skip most of it. But since this guide covers everything you need to set up a server, you may find some useful instructions that apply to your situation.
Before we start, we assume that you already have:
Access to an Ubuntu server. You may get it by launching an instance at AWS EC2 (Amazon Web Services - Elastic Compute Cloud), or renting a VPS (Virtual Private Server) from a hosting provider, or you may get it from your system administrator. You need to have:
- The host name or IP address of your server.
- The username and the private key or password of a user with sudo rights. On
a clean installation of AWS EC2 or a VPS, you may only have the initial
ubuntu
orroot
user. We will create a normal user as soon as possible.
A domain name with the DNS set to resolve to the IP address of your server. If your domain is
example.com
, we assume thatexample.com
andwww.example.com
resolve to your server.An SSL certificate for your domain name (
example.com
andwww.example.com
). You can purchase a domain name and SSL certificate, or get it from your system administrator. For the certificate you should have three files like:example_com.ca-bundle
example_com.crt
example_com.key
Access to an SMTP server to send email associated with your domain. Again, you can purchase email hosting from a hosting provider or get it from your system administrator.
# Connect
First you need to connect to your Ubuntu server from your workstation. Instructions:
# Create user
If you logged in with the initial ubuntu
or root
user, you should first
create a normal user and give it sudo rights. You can also use the following
instructions to create additional users.
- Enter this command (
sudo
is not needed if you areroot
):$ sudo adduser <NEWUSER>
- When asked, enter a password.
- You are asked for further details, which are optional.
- When the user is created, grant the sudo rights and add the user to relevant
groups:
$ sudo usermod -a -G sudo,adm,www-data <NEWUSER>
Then create an SSH key pair for the user if you don’t have one yet.
- Open Terminal on your computer and enter:
$ ssh-keygen
- You are asked to enter the file in which to save the key. If you are creating
a user for yourself, accept the default
~/.ssh/id_rsa
. Otherwise enter something else, such asusername_key
. - When asked for the passphrase, just press Enter.
- You should now have two files. If you chose the default
~/.ssh/id_rsa
, you will have:id_rsa
: the private keyid_rsa.pub
: the public key
- Copy the files to a safe location so you can restore them if needed.
Upload the public key to the server.
- Still in the terminal on your computer, enter this command:At
$ scp .ssh/id_rsa.pub <CURRENTUSER>@<HOSTNAME>:~
<CURRENTUSER>
fill in the user that you are currently logged in with, not the new user that we are still setting up.
You can change the public key path.ssh/id_rsa.pub
if you chose a different location. - Now the public key is at your server. You can close the terminal on your computer.
- Go back to your server connection.
- Enter these commands:
$ sudo mkdir -p /home/<NEWUSER>/.ssh $ cat id_rsa.pub | sudo tee -a /home/<NEWUSER>/.ssh/authorized_keys $ rm id_rsa.pub $ sudo chown -R <NEWUSER>:<NEWUSER> /home/<NEWUSER>/.ssh $ sudo chmod 700 /home/<NEWUSER>/.ssh $ sudo chmod 600 /home/<NEWUSER>/.ssh/authorized_keys
- Close the connection with
exit
.
Now you can connect with the new user (Windows, Mac) using the new private key.
# Secure SSH access
You can further secure the SSH server by disabling SSH access for the root
user and disabling access with a password, so a private key is required.
- Connect to your server and edit
sshd_config
in nano:$ sudo nano /etc/ssh/sshd_config
- Find the following options and change them to
no
:PermitRootLogin yes UsePAM yes PasswordAuthentication yes
- Add this line:
ChallengeResponseAuthentication no
- Save the file with Ctrl+S and close the editor with Ctrl+X.
- Restart the SSH server with:IMPORTANT: Without your private key, you will no longer be able to connect to your server through SSH.
$ sudo service ssh restart
# Update
Run an update of the software. You need to repeat this from time to time to keep your server up-to-date.
- Enter these commands:
$ sudo apt update $ sudo apt upgrade
- You may need to reboot after installing the updates:
$ sudo reboot
- This will close your connection. Reconnect later when the machine has rebooted.
# Firewall
The firewall should only allow the following inbound ports:
- 22 (SSH): only your IP address
- 80 (HTTP): anywhere
- 443 (HTTPS): anywhere
Sometimes you, as a developer or administrator, will need access to other ports. Do not open such ports in your Firewall. You can access other ports through an SSH tunnel (Windows, Mac).
If you use AWS EC2, you can configure this in the security groups. Otherwise you can configure the firewall in Ubuntu.
# AWS EC2 Security Groups
- From your EC2 dashboard, in the left-hand sidebar, choose Network & Security > Security Groups.
- Click the security group ID that you are using.
- Click Edit inbound rules.
Add the following rules:
Type | Protocol | Port range | Source |
---|---|---|---|
HTTP | TCP | 80 | Anywhere-IPv4: 0.0.0.0/0 |
HTTPS | TCP | 443 | Anywhere-IPv4: 0.0.0.0/0 |
SSH | TCP | 22 | Custom: <IP-ADDRESS>/32 |
You can add multiple SSH rules for all IP addresses or ranges that you want to allow.
# Ubuntu firewall
First allow access to port 22 (SSH). You can allow access from anywhere, or for extra security only from your IP address. For access from anywhere:
$ sudo ufw allow 22
For access from a certain IP address:
$ sudo ufw allow from <IP-ADDRESS> to any port 22
You can also use an IP mask like
192.168.1.0/24
.IMPORTANT: You must configure this correctly before you activate the firewall in the next step. Otherwise you can no longer access your server through SSH. If you restrict access to your IP address, you will lose SSH access if your address changes.
Then allow the other ports from anywhere and activate the firewall:
$ sudo ufw allow 80 $ sudo ufw allow 443 $ sudo ufw enable
# Apache
We will use Apache (opens new window) as a secure proxy in front of the applications that we install in Docker containers. First we will install Apache and create a general configuration for our server.
# Install
Enter this command:
$ sudo apt install apache2
Enable modules:
$ sudo a2enmod proxy $ sudo a2enmod proxy_ajp $ sudo a2enmod proxy_html $ sudo a2enmod proxy_http $ sudo a2enmod rewrite $ sudo a2enmod ssl
You can restart Apache any time to load your configuration changes:
$ sudo service apache2 restart
# SSL certificate
Now you need to upload the certificate files from your computer to the server. Upload the three files like:
example_com.ca-bundle
example_com.crt
example_com.key
Instructions to upload files:
Upload the files to your home directory on the server. Then we move them to a
secure location that is only accessible to Apache and to users in group
www-data
.
- After uploading the files, enter the following commands. Use your domain
instead of
example_com
.$ cd /etc/apache2 $ sudo mkdir ssl $ sudo chown www-data:www-data ssl $ sudo chmod 750 ssl $ cd ssl $ sudo mv ~/example_com.* . $ sudo chown www-data:www-data * $ sudo chmod 640 *
We will load the certificate in Apache in the next section.
# Secure file access
By default Apache gives access to the files in /usr/share
and /var/www
.
In our setup we serve everything through proxies to Docker containers, so we
do not need public access to these files. It is best to deny access to files
that are not needed. At least we recommend to deny access to /usr/share
as
this is used for developer applications such as stand-alone phpMyAdmin, which
should be private. If you need those applications, you should configure Apache
so that they are provided at an alternative port such as 8080 and access them
through an SSH tunnel (see Firewall).
You can deny access to /usr/share
and /var/www
with the following steps.
Edit
apache2.conf
in nano:$ cd /etc/apache2 $ sudo nano apache2.conf
Find these lines:
<Directory /> Options FollowSymLinks AllowOverride None Require all denied </Directory> <Directory /usr/share> AllowOverride None Require all granted </Directory> <Directory /var/www/> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory>
Comment the following lines:
# <Directory /usr/share> # AllowOverride None # Require all granted # </Directory> # <Directory /var/www/> # Options Indexes FollowSymLinks # AllowOverride None # Require all granted # </Directory>
Save the file with Ctrl+S and close the editor with Ctrl+X.
# Sites
Sites are the applications and services that we want to make available. They can be public sites for end users, such as the SenSeeAct web application and API, or they can be private sites for administrators and developers, such as phpMyAdmin. Our applications and services will be provided by private Docker containers. For the ones that we want to make public, we will install sites in Apache as proxies to the Docker containers. The private ones are left as Docker containers. They can be accessed through an SSH tunnel (see Firewall).
In our configuration of Apache we consider that you can have additional sites of your own. If you install any private sites directly in Apache, we recommend to install them at an alternative port such as 8080 and access them through an SSH tunnel.
The Apache configuration allows for available sites that can be enabled and
disabled indepedently. This is done in the directories
/etc/apache2/sites-available
and /etc/apache2/sites-enabled
. We will set it
up with these considerations:
- We enable secure
https://
by installing the SSL certificate. - Unsecure
http://
is automatically redirected to securehttps://
. - We support specific subdomains such as
myapp.example.com
if you need them. Note that you need a wildcard SSL certificate for that. - Everything else defaults to
https://www.example.com/
. - You can enable or disable various sites under
www.example.com
.
We start with some defaults in /etc/apache2/sites-available
. Note that the
files will be imported in alphabetical order. This is significant because Apache
will resolve incoming requests to the first match that it encounters.
- Edit
000-default.conf
in nano:$ cd /etc/apache2/sites-available $ sudo nano 000-default.conf
- Replace the content with the following. Use your domain instead of
example_com
.<VirtualHost *:80> DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> <VirtualHost *:443> DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on SSLCertificateFile /etc/apache2/ssl/example_com.crt SSLCertificateKeyFile /etc/apache2/ssl/example_com.key SSLCertificateChainFile /etc/apache2/ssl/example_com.ca-bundle </VirtualHost>
- Save the file with Ctrl+S and close the editor with Ctrl+X.
If you want to support any subdomains like myapp.example.com
, configure them
next, so they take precedence over the default www.example.com
. Configure a
subdomain with the following steps. You can skip this if you don’t use any
subdomain.
- Create file
001-myapp.conf
in nano. Use your subdomain instead ofmyapp
.$ sudo nano 001-myapp.conf
- With the following content. Use your subdomain instead of
myapp.example.com
.<VirtualHost *:80> ServerName myapp.example.com RedirectPermanent / https://myapp.example.com/ </VirtualHost> <VirtualHost *:443> ServerName myapp.example.com # Configure the site here </VirtualHost>
- Save the file with Ctrl+S and close the editor with Ctrl+X.
After the custom subdomains, we get to the default www.example.com
. We will
set up an additional layer of sites that you can enable or disable independently
within the domain of www.example.com
. We create a directory www-available
.
- Enter these commands:
$ sudo mkdir www-available
- Create file
100-www-default.conf
in nano.$ sudo nano 100-www-default.conf
- With the following content. Use your domain instead of
example.com
.<VirtualHost *:80> # Redirect everything on http to https://www.example.com/ ServerName www.example.com ServerAlias example.com ServerAlias *.example.com RedirectPermanent "/" "https://www.example.com/" </VirtualHost> <VirtualHost *:443> ServerName www.example.com IncludeOptional sites-enabled/www-enabled/*.conf </VirtualHost> <VirtualHost *:443> # Redirect everything remaining on https to https://www.example.com/ # This section has to be after the previous section, so that we do not # redirect www.example.com to itself. ServerName example.com ServerAlias *.example.com RedirectPermanent / https://www.example.com/ </VirtualHost>
- Save the file with Ctrl+S and close the editor with Ctrl+X.
Finally set up the directory sites-enabled
.
- Enter these commands:
$ cd /etc/apache2/sites-enabled $ sudo ln -sf ../sites-available/0*.conf ../sites-available/1*.conf . $ sudo mkdir www-enabled
We will install SenSeeAct in www-enabled
later.
# Default site
When we install SenSeeAct, we will install the web application at one of these
URLs:
https://www.example.com/
or https://www.example.com/senseeact/
And we install the API at:
https://www.example.com/servlets/senseeact/
If you choose to install the web application at
https://www.example.com/senseeact/
and the user goes to
https://www.example.com/
, they will see a “forbidden” message. Below are some
options to configure that URL.
Option 1: Redirect to SenSeeAct or another site
- Edit
100-www-default.conf
in nano:$ cd /etc/apache2/sites-available $ sudo nano 100-www-default.conf
- Find this section:
<VirtualHost *:443> ServerName www.example.com IncludeOptional sites-enabled/www-enabled/*.conf </VirtualHost>
To redirect to SenSeeAct:
- Before
</VirtualHost>
add this line:RedirectMatch "(^/$)|(^/index.php.*$)|(^/index.html.*$)" "/senseeact/"
To redirect to another site:
- Before
</VirtualHost>
add a line like this:RedirectMatch "(^/$)|(^/index.php.*$)|(^/index.html.*$)" "https://www.othersite.com/"
Finally save the file with Ctrl+S and close the editor with Ctrl+X.
Option 2: Install a default site in /var/www/html
If you disabled access to /var/www
earlier, then re-enable it:
- Edit
apache2.conf
in nano:$ cd /etc/apache2 $ sudo nano apache2.conf
- Enable this section:
<Directory /var/www/> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory>
- Save the file with Ctrl+S and close the editor with Ctrl+X.
- Copy the files for the default site to
/var/www/html
.
# Restart Apache
We have finished the configuration of Apache. Now restart Apache to activate the changes.
- Enter this command:
$ sudo service apache2 restart
# Docker
https://www.docker.com/ (opens new window)
- Install Docker with these commands:
$ sudo apt update $ sudo apt install ca-certificates curl gnupg lsb-release $ sudo mkdir -p /etc/apt/keyrings $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg $ echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null $ sudo apt update $ sudo apt install docker-ce
- Add your user to the
docker
group:$ sudo adduser $USER docker