Web 0: The site's tech stack

So I've been interested in the indie, "old web" and hobbyist web development scene for a little bit. To a great degree, sites in such communities tend to be static HTML/CSS/JS setups hosted on free/low cost static site hosts such as NeoCities or similar platforms.

My site's a bit different in this regard. I've been writing in PHP since about 2007 or so, and accordingly, my site is a full on LAMP stack based site written in PHP and using a MySQL database for a backend...and unlike a lot of modern sites that use the same tech stack, I'm not using a pre-made CMS like WordPress to accomplish this.

I feel like this sort of technology can be useful to the community, but is pretty rarely discussed, since a lot of the community tends to focus on static site development.

To this ends, while I may not be a professional developer in any capacity, I'm going to put out a few articles explaining how my site works so that people unfamiliar with PHP can see an example of a simple site built in it. Hopefully this is helpful to someone, and if anyone has improvements or corrections to make, please feel free to reach out through the site's message board. I'm always open to good insights and learning opportunities!

This article's going to go over how to install the basic components of the site, and can be used as deployment notes if needed for reference.

Network overview

data/web0/arch.png

The above sorta lays out the basic structure of this site's infrastructure. As can be seen, there are several components we can go over:

  • The LAMP (web) server itself
  • The host based IDS and Firewall
  • OpenVPN
  • The Wazuh SIEM manager and agents

The LAMP server

The LAMP is a VPS hosted by Namecheap, who also provide the domain name and DNS services. Particularly, this is on one of their "Quasar" units, which is a KVM based VM with 8 Cores, 16GB RAM and 3TB monthly bandwidth. This is their mid-tier VPS product, and is about $15/month. DNS and the domain name are configured in the VPS panel through Namecheap's web site, so that's a bit out of scope for this article.

This particular instance is running Ubuntu Server, but other operating systems are available.

Here's how to replicate the server environment.

OpenVPN and Firewall config.

Immediately upon renting the VPS and getting our first access, we want to get some basic security set up so that we don't have remote access protocols like SSH or VNC exposed directly to the internet.

Firstly, we'll need to install OpenVPN as follows:


wget https://git.io/vpn -O openvpn-install.sh
sudo chmod +x openvpn-install.sh 
sudo bash openvpn-install.sh 

This will run the install script, which will not only install the server, but also prompt us to generate a client key file. It also creates a hard iptables entry for OpenVPN to be able to receive through the firewall.

The user key generated here was then exfiltrated back to my jumpbox on my local network. Iirc, this was done merely by catting the file out and copying it manually.

Once it's installed, we can check whether it's running with:


sudo systemctl status openvpn-server@server.service

If it isn't running, use systemctl enable to enable it and then systemctl start to bring it online.

Once it's confirmed up, test it to ensure that you can connect from a remote host to the VPN and establish an SSH connection over the tunnel.

I do this like so from my jumpbox:


sudo -b openvpn user_key.ovpn
ssh user@10.8.0.1

Once we have OpenVPN up and we've confirmed that we can reach SSH over the tunnel, we can roll out our firewall and secure the server.

Firstly, we'll want to add an exception for SSH over the VPN tunnel:


sudo ufw allow from 10.8.0.2 proto tcp to any port 22

Here, 10.8.0.2 is my jumpbox.

At this point, we can enable the firewall and cutoff all external access to the server. WARNING: ensure that you can reach SSH over OpenVPN before running the following; otherwise you'll lock yourself out of the server.


sudo ufw enable

Installing the LAMP stack

LAMP stands for "Linux, Apache, MySQL and PHP" and is the core tech stack used to actually serve the site. We can get these components installed as follows.

sudo apt install apache2
sudo apt install mysql-server
sudo apt install php libapache2-mod-php php-mysql

This gives us the core of the LAMP stack. We'll also need to following 2 PHP modules, as they are dependencies for some of my scripts.

sudo apt install php-gd
sudo apt install php-mbstring

Also installed on this server is the ModSecurity WAF component of Apache:

sudo apt-get install libapache2-mod-security2
sudo apt-get install modsecurity-crs

This system basically makes it so that if malicious activity is detected coming through a page, a 403 is returned instead of letting anything through. This causes numerous problems when it's overaggressive, so multiple rule and page exceptions have been added to the server configuration. These won't be covered, as they're rather extensive.

After we get these base components installed, we'll want to configure some things with MySQL:

sudo mysql_secure_installation

There are numerous other things that we'll cover about MySQL later as they come up in future articles detailing how particular scripts work.

Next we'll get certbot setup so that we can use a Let's Encrypt self signed cert for HTTPS:


sudo apt-get install snapd
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --apache

This should automatically get a cert for us and configure Apache to use HTTPS.

After this, we can also open the firewall for Apache:


sudo ufw allow ‘Apache Full’

The last thing really to do would be to go over a general hardening guide, such as this one. Steps like this can help tighten security a bit and make enumeration for vulnerabilities a bit more difficult for attackers.

Suricata

Suricata is an IDS. Often, in enterprise installs, you may find it installed on an inline network appliance, but in this situation, it is installed on the web server itself and serves as a Host-based intrusion detection system.

Since this will be integrated with the Wazuh SIEM, I generally follow the instructions for install that they provide here.

Note that once we get Suricata rolling, we need to ensure that logrotate is setup to work with it properly. Otherwise, Suricata will fill up the entire disk with IDS logs over time.

sudo nano /etc/logrotate.d/suricata

And then populate it thusly:


/var/log/suricata/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 suricata suricata
    postrotate
        systemctl reload suricata > /dev/null 2>&1 || true
    endscript
}

We can then test this like so:

sudo logrotate -d /etc/logrotate.d/suricata

The SIEM Agent

A SIEM is more or less a platform that aggregates logs from your network and then parses these and passes them through a rule engine so that you can receive alerts about security issues going on in the environment.

Typically, these work by having agents on endpoints in the network that then ship local logs to the central SIEM server for processing. Once at the server, the logs are parsed into a format understandable by the SIEM, and then rules (which are more or less search and matching patterns, like regex) are applied to the parsed logs in order to generate alerts that can be used to see security incidents.

This site is monitored by a Wazuh SIEM instance. We'll cover how to install that up ahead when we talk about the jump box. For now, let's configure the Wazuh Agent on the LAMP server so that we can collect logs.

For simplicity, we should follow Wazuh's own documentation for the basic parts of this process.

After this, we'll need to configure some specifics for the agent to make sure we're pulling in the right logs:

Firstly, we want to make sure the server address points back to our SIEM server (which we'll talk about setting up later):


<ossec_config>
  <client>
    <server>
      <address>10.8.0.2</address>
      <port>1514</port>
      <protocol>tcp</protocol>
    </server>
    <config-profile>ubuntu, ubuntu22, ubuntu22.04</config-profile>
    <notify_time>10</notify_time>
    <time-reconnect>60</time-reconnect>
    <auto_restart>yes</auto_restart>
    <crypto_method>aes</crypto_method>
  </client>

Big deal is to make sure our <address> is correct.

Additionally, we'll want to ensure that we add a config directive for Suricata log ingestion.


<localfile>
  <log_format>json</log_format>
  <location>/var/log/suricata/eve.json</location>
</localfile>

This should be added towards the end of /var/ossec/etc/ossec.conf

At this, we should be able to issue sudo systemctl enable wazuh-agent and sudo systemctl start wazuh-agent to start the agent service, however, we still havn't set up the SIEM manager yet, so this won't do anything...for now.

The Jumpbox and Wazuh VM

The jump box serves as our connection into the LAMP server from our local network over VPN and also houses the Wazuh SIEM server.

OpenVPN

In order to reach the LAMP once we lock down access to the server to the VPN only, we'll need to install OpenVPN.

sudo apt-get install openvpn

Once we have it installed, we need to bring over the user key we created on the LAMP server earlier, and then establish the VPN connection in a way that lets it run in the background:


sudo -b openvpn user_key.ovpn

Once this is established, during provisioning, we should connect to the LAMP from the Jumpbox via the VPN interface. As mentioned before, ensuring that we can reach the LAMP via VPN should be done before we lock down the firewall and deny SSH to the public internet -- this is to ensure that we don't lock ourselves out of the server.

Once the VPN connection is established , we can proceed to setting up the SIEM supervisor.

Setting up Wazuh SIEM manager

I have the SIEM setup as a VM that runs under Virtual Box on the Jumpbox.

Obviously, we'll first need to install Virtual Box:


sudo apt-get install virtualbox
sudo apt-get install virtualbox-ext-pack

With the hypervisor installed, we need to pull down the VM appliance for the SIEM.


wget https://packages.wazuh.com/4.x/vm/wazuh-4.5.2.ova

Note that while I'm using 4.5.2 as the example version, Wazuh is on higher versions now, which can be found here.

Once we have it, we need to import it and configure it:


VBoxManage import wazuh-4.5.2.ova --dry-run
VBoxManage import wazuh-4.5.2.ova --vsys 0 --memory 8196 --cpus 2 --eula accept
VBoxManage modifyvm "Wazuh v4.5.2 OVA" --vrde on
VBoxManage modifyvm "Wazuh v4.5.2 OVA" --graphicscontroller VMSVGA
VBoxManage startvm "Wazuh v4.5.2 OVA" --type headless

This should import it and give us some basic config. Next, in order to let the VM receive over the OpenVPN connection, we need to configure the networking:


VBoxManage modifyvm "Wazuh v4.5.2 OVA" --nictype1 virtio
VBoxManage modifyvm "Wazuh v4.5.2 OVA" --natpf1 "wazuh_agent, tcp, 0.0.0.0, 1514,,1514"
VBoxManage modifyvm "Wazuh v4.5.2 OVA" --natpf1 "wazuh_enrollment, tcp, 0.0.0.0, 1515,,1515"
VBoxManage modifyvm "Wazuh v4.5.2 OVA" --natpf1 "wazuh_frontend, tcp, 0.0.0.0, 443,,443"

This switches the networking mode of the VM to virtio, and then configures some ports that we need. 1514 and 1515 are communications ports that the SIEM uses to ingest logs from the agents. 443 is for the Wazuh Dashboard, which is where we can actually do searches in the SIEM using a webapp. This will be located at https://<IP of the Jumpbox>/.

Once this is done, we should have a basic Wazuh siem ready to go. Let's fire it up and see if it works:


VBoxManage startvm "Wazuh v4.5.2 OVA" --type headless

Give it a minute and then we should be able to reach the SIEM dashboard. If the agent for the LAMP server is not registered, give the service a restart on the LAMP server with sudo systemctl restart wazuh-agent.

At this point, our basic infrastructure should be fully provisioned.