Prerequisites - Updated September 2024

  • Ubuntu Server LTS 24.04.x (server install, basic - no GUI or other options), 16GB RAM, 200GB HDD
  • Latest postgreSQL 17, Adoptium JDK 21
  • Latest Tomcat 10.1.x

Basics:

  • sudo apt update && sudo apt upgrade -y
  • sudo apt install zip unzip
  • sudo touch /etc/cloud/cloud-init.disabled
  • sudo apt purge cloud-init -y
  • sudo rm -Rf /etc/cloud
  • apt-get install gnupg
  • sudo apt-get -y install yamllint
  • sudo apt install ufw
  • sudo apt install nano
  • sudo apt install whois
  • sudo timedatectl set-timezone UTC
  • sudo timedatectl set-ntp on
  • sudo apt update && sudo apt upgrade -y
  • sudo apt autoremove

Basic Security

Ubunutu firewall basic configuration, handy commands:

  • sudo ufw enable | disable
  • sudo ufw status numbered ( see rules )
  • sudo ufw delete X ( delete a rule by number )
  • sudo ufw reload ( after rule changes )
sudo ufw allow from [trusted IP] to any port 22 ( if sshd is on non-standard port use that port )
sudo ufw allow from any to any port 80
sudo ufw allow from any to any port 443

Use fail2ban to protect against brute force/dictionary ssh attacks and mal-formed http requests. - tutorial

sudo apt install fail2ban

Basic sshd refinements. (we recommend using ssh keys tutorial)

sudo nano /etc/ssh/sshd_config

Protocol 2
Port XXX ( change port, config ufw to allow the selected port )
ListenAddress x.x.x.x ( if multiple IP, bind to one IP )
LogLevel VERBOSE
AllowUsers user_1 user_2 ( list logins that are allowed to ssh )
LoginGraceTime 30
PermitRootLogin no
MaxAuthTries 3
HostbasedAuthentication no
IgnoreRhosts yes
PermitEmptyPasswords no
AllowTcpForwarding no
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 0
MaxStartups 2

sudo systemctl restart ssh

PostgreSQL

Installation Instructions: https://www.postgresql.org/download/linux/ubuntu/

Create the file repository configuration:

sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

Import the repository signing key:

wget --no-check-certificate -q -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

Update the package lists:

sudo apt-get update

sudo apt-get -y install postgresql-17
Tune postgresql: https://pgtune.leopard.in.ua/

File to edit when tuning PG:

sudo nano /etc/postgresql/17/main/postgresql.conf

Starting (or stopping) postgres: ( stop | start | restart )

sudo pg_ctlcluster 17 main restart


Java 21

Install Java JDK 21

sudo mkdir /usr/lib/jvm
cd /usr/lib/jvm
Direct from Adoptium https://adoptium.net
sudo wget --inet4-only https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz --no-check-certificate
Extract download
sudo tar -xvzf OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz

Append the following command to open the environment variables file.

sudo nano /etc/environment
JAVA_HOME="/usr/lib/jvm/jdk-21.0.4+7"

Run from command line.

sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk-21.0.4+7/bin/java" 0
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk-21.0.4+7/bin/javac" 0
sudo update-alternatives --set java /usr/lib/jvm/jdk-21.0.4+7/bin/java
sudo update-alternatives --set javac /usr/lib/jvm/jdk-21.0.4+7/bin/javac

Check Version

java -version
sudo update-alternatives --config java
sudo update-alternatives --display java


Tomcat 10.1

Install 10.1.33

For security purposes, Tomcat should run under a separate, unprivileged user. Run the following command to create a user called tomcat:

sudo useradd -m -d /opt/tomcat -U -s /bin/false tomcat

To install Tomcat, you’ll need the latest Core Linux build for Tomcat 10

cd /tmp
wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.33/bin/apache-tomcat-10.1.33.tar.gz --no-check-certificate
sudo tar xzvf apache-tomcat-10.1.33.tar.gz -C /opt/tomcat --strip-components=1

Since you have already created a user, you can now grant tomcat ownership over the extracted installation by running:

sudo chown -R tomcat:tomcat /opt/tomcat/
sudo chmod -R u+x /opt/tomcat/bin

The systemd service that you will now create will keep Tomcat quietly running in the background. The systemd service will also restart Tomcat automatically in case of an error or failure.

sudo nano /etc/systemd/system/tomcat.service

Paste the content bellow in the new tomcat.service file.

[Unit]
Description=Tomcat
After=network.target

[Service]
Type=forking

User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/jdk-21.0.4+7"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms1024M -Xmx2048M -server -XX:+UseParallelGC"

ExecStart=/usr/bin/authbind --deep /opt/tomcat/bin/startup.sh - updated
ExecStop=/usr/bin/authbind --deep /opt/tomcat/bin/shutdown.sh - updated

RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

Run systemctl daemon-reload to reload units.

After installing tomcat, download the latest CoCCA RDAP ROOT.war and copy it to /opt/tomcat/webapps/.

sudo systemctl stop tomcat
cd /opt/tomcat/webapps/
rm -fr ROOT
rm -fr docs
rm -fr examples

Rename server.xml and context.xml files to server.bak and context.bak in /opt/tomcat/conf/

Download the default CoCCA tomcat config files (server.xml & context.xml).

cd /opt/tomcat/conf/
rm -fr server.xml
rm -fr context.xml

Edit the context.xml file for db name, username, password

sudo nano /opt/tomcat/conf/context.xml

Create a folder for the CoCCA rdap.properties config file.

mkdir /opt/tomcat/rdap/
cd /opt/tomcat/rdap/

letsencrypt

If you want to get started with a free https certificate to match your host name, we suggest https://letsencrypt.org

If using nginx as a reverse proxy it is not nessesary to use a jks. The SSL .pem certs can be in refferences in the nginx config file. Tomcat listens on port 127.0.0.1:8080 without TLS

Using nginx as a reversr proxy is the recommnded configuration.

sudo apt install certbot

Stop tomcat webserver temporarily.

sudo systemctl stop tomcat

Request a new certificate

mkdir /opt/tomcat/jks
cd /opt/tomcat/jks/
sudo certbot certonly --standalone

Create p12 (one long string/command)

openssl pkcs12 -export -name sslcertificate -in /etc/letsencrypt/live/registry.example.tld/fullchain.pem -inkey /etc/letsencrypt/live/registry.example.tld/privkey.pem -out registry.example.tld.p12

Create Java keystore and import p12 (one long string/command):

/usr/lib/jvm/jdk-21.0.4+7/bin/keytool -importkeystore -destkeystore registry.example.tld.jks -srckeystore registry.example.tld.p12 -srcstoretype pkcs12 -alias sslcertificate

Edit tomcat server.xml config file to enable https certificate:

sudo nano /opt/tomcat/conf/server.xml

Add jks file name and password for the custom jks created above.

Restart tomcat to see CoCCA rdap https client.

sudo systemctl restart tomcat


Secure Tomcat

Running Tomcat on Privileged Port 443

By default tomcat listens on port 8080 for HTTP and 8443 for HTTPS. If you want Tomcat to listen on the standard HTTP (80) and HTTPS (443) ports, some aditional config is required. Ports below 1024 are considered privileged ports on Linux and only available to processes running as root. Authbind allows Tomcat to run on port 80 and 443.

sudo apt install authbind

Assuming a user tomcat was created as per the tutorial

sudo touch /etc/authbind/byport/443
sudo chmod 500 /etc/authbind/byport/443
sudo chown tomcat /etc/authbind/byport/443
Edit JDK path, name and password
sudo nano /opt/tomcat/conf/server.xml
systemctl daemon-reload
sudo systemctl restart tomcat
ps auxwww | grep -v grep | grep tomcat

When ready for production, make sure tomcat manager is disabled by un-commenting (enable) the valve restrictions in the two files bellow.

sudo nano /opt/tomcat/webapps/manager/META-INF/context.xml
sudo nano /opt/tomcat/webapps/host-manager/META-INF/context.xml

Start on reboot

sudo systemctl enable tomcat

WHOIS p43

OPTIONAL - By default CoCCA runs a whois server on port 4300 of the RDAP server. If you want to run a port 43 service you need to setup port forwarding in UFW.

Step 1
sudo nano /etc/ufw/sysctl.conf
IPv4 - uncomment net/ipv4/ip_forward=1.
IPv6 - uncomment
net/ipv6/conf/all/forwarding=1
net/ipv6/conf/default/forwarding=1
Save and Exit
Step 2
For IPv4 - sudo nano /etc/ufw/before.rules
For IPv6 - sudo nano /etc/ufw/before6.rules

Add a NAT table after the table that starts with *filter and ends with COMMIT, at bottom of the file.

# Start port 43 WHOIS NAT
*nat
:PREROUTING ACCEPT [0:0]
-A PREROUTING -p tcp --dport 43 -j REDIRECT --to-port 4300
COMMIT
# End port 43 WHOIS NAT

Save and Exit
sudo ufw allow 43/tcp
sudo ufw allow 4300/tcp
sudo systemctl restart ufw

NGINX proxy

OPTIONAL - For better security and caching install nginx reverse proxy.

sudo apt update
sudo apt install nginx
sudo nano /etc/nginx/sites-available/your_domain

When creating the config file above, replace your_domain with rdap.nic.tld or whatever host name is appropriate.

Paste the contenxt below in the empty file, replace your_domain with the rdap-whois host name(s), for example whois.nic.tld rdap.nic.tld, for the .pem files locate the correct path on your server.

# HTTP redirect
server {
listen 80;
listen [::]:80;
server_name rdap.nic.tld;
location / {
return 301 https://rdap.nic.tld$request_uri;
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
keepalive_timeout 70;
ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
server_name rdap.nic.tld whois.nic.tld;
if ($request_method !~ ^(GET|HEAD|POST)$ )
{
return 405;
}
location / {
proxy_pass http://127.0.0.1:8080;
include proxy_params;
proxy_cache static_cache;
proxy_cache_valid 200 12h;
proxy_cache_valid 404 1h;
proxy_ignore_headers "Cache-Control" "Expires";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header X-Proxy-Cache $upstream_cache_status;
}
}

Save and exit, with nano you can do this by hitting CTRL+O then CTRL+X.

Next, enable this configuration file by creating a link from it to the sites-enabled directory that Nginx reads at startup:

sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/

NGINX uses the default linked configuration file. Creating a reverse proxy requires creating and linking a custom file. To avoid any potential conflicts, use the following command:

sudo unlink /etc/nginx/sites-enabled/default

sudo nginx -t

To configure NGINX to launch on reboot automatically, enable the service with:

sudo systemctl enable nginx

Create a Non-Root User

sudo useradd -m -d /opt/nginxuser -U -s /bin/false nginxuser

Grant nginxuser Necessary Permissions

sudo chown -R nginxuser:nginxuser /var/log/nginx
sudo chown -R nginxuser:nginxuser /var/lib/nginx

Now, Open the Nginx configuration file in a text editor.

sudo nano /etc/nginx/nginx.conf

Within the configuration file, locate the user directive (top of the conf file), and set it to the non-root user you created.

  • user nginxuser;
  • worker_connections 1024;
  • uncomment server_tokens off;

Save and exit, with nano you can do this by hitting CTRL+O then CTRL+X.

Test the Configuration

sudo nginx -t

Edit tomcat server.xml config file and comment out the Connector port="443" section and add a new section:

Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1" connectionTimeout="20000"/>

sudo nano /opt/tomcat/conf/server.xml
sudo systemctl restart tomcat
sudo systemctl restart nginx

Check the process using the following command to ensure that Nginx is running with the non-root user.

ps aux | grep nginx
Rate Limit http(s) - to help prevent DDoS attacks.

Add these lines to /etc/ufw/before.rules

# End required lines

Add these lines

# Limit to 5 concurrent connections on port 80/443 per IP
-A ufw-before-input -p tcp --syn --dport 80 -m connlimit --connlimit-above 5 -j DROP
-A ufw-before-input -p tcp --syn --dport 443 -m connlimit --connlimit-above 5 -j DROP
# Limit to 5 connections on port 80/443 per 2 seconds per IP
-A ufw-before-input -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set
-A ufw-before-input -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --update --seconds 2 --hitcount 5 -j DROP
-A ufw-before-input -p tcp --dport 443 -i eth0 -m state --state NEW -m recent --set
-A ufw-before-input -p tcp --dport 443 -i eth0 -m state --state NEW -m recent --update --seconds 2 --hitcount 5 -j DROP

Reload the filewall rules
sudo ufw reload