On-premise web app with Apache and CentOS

On-premise web app with Apache and CentOS

The HR department needs an app to register employees as we continue growing.

We will set up a CentOS VM and use Apache as the web server, it will be accessible via HTTP and HTTPs (we will bind an SSL certificate to the web app) on its private IP, and then we will be setting up a proper Fully qualified domain name (FQDN), finally we will use Cloudflare tunnel to securely publish our web app on the Internet.

Specs:

  • 1 vCPU

  • 1 Disk (40GB)

  • 2 GB Ram

  • IP: 10.100.100.11/24

Setting up Hostname

Let’s change the hostname for our VM to BBM-WEB01:

sudo su
hostname BBM-WEB01

Setting up Apache

next, we can install Apache on our CentOS VM by running:

yum install httpd

Enter y:

After that, we will have the Apache server installed:

We can also verify by running:

rpm -qa | grep http

Let’s now to configure the index.html file:

cd /var/www/html/
ls -ltr
nano index.html

By default the Firewall (firewalld) will block incoming connections to port 80 and all ports, let’s disable it for now:

systemctl stop firewalld

After that, we can run the following command to make sure it’s disabled:

systemctl status firewalld

Then we can visit: http://10.100.100.11 and see the website opening

Configure SSL / HTTPS

As we noticed, we are accessing our web server via HTTP, which is an insecure protocol, let’s enable HTTPS, the secure version that uses SSL/TLS and create a self signed SSL certificate.

Let’s install the mod_ssl on our VM:

yum install mod_ssl

Now let’s create a folder to store (with full Read/Write permissions) the certificate and the private key:

mkdir /etc/ssl/private
chmod 700 /etc/ssl/private

Let’s create now our certificate with its private key:

  • openssl req: Initiates a certificate signing request

  • -x509: Specifies that you want to create a self-signed certificate instead of a certificate request

  • -nodes: Creates a key without a passphrase (No DES encryption)

  • -days 365: Certificate will be valid for 365 days

  • -newkey rsa:2048: Creates a new 2048-bit RSA key pair

  • -keyout /etc/ssl/private/ssl.key: Saves the private key to this location

  • -out /etc/ssl/private/ssl.crt: Saves the certificate to this location

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/ssl.key -out /etc/ssl/private/ssl.crt

After that, we will be prompted to fill out:

  • Country Name: US

  • Status or Province name (full name): Texas

  • Locality Name (City): Houston

  • Organization Name (Company): BeyondBareMetal

  • Organizational Unit Name: IT

  • Common Name: 10.100.100.11

    Email Address:

Then we can verify the certificate and key have been generated and stored successfully:

cd /etc/ssl/private/
ls -ltr

Now for additional security let’s generate Diffie-Hellman parameters:

This file is commonly used in conjunction with SSL/TLS configurations (especially in Apache and Nginx) to provide additional security. The Diffie-Hellman parameters help ensure that even if a private key is compromised in the future, past communications remain secure.

openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
  • openssl dhparam: Command to generate Diffie-Hellman parameters.

  • -out /etc/ssl/certs/dhparam.pem: Specifies where to save the generated parameters.

  • 2048: Sets the key size to 2048 bits.

Let’s now append the DH parameters to our certificate:

  • cat /etc/ssl/certs/dhparam.pem: Reads the content of the DH parameters file

  • |: Pipes the output to the next command

  • tee -a /etc/ssl/certs/ssl.crt:

    • tee: reads from standard input and writes to both standard output and files

    • -a: means append (rather than overwrite)

    • Adds the DH parameters to the end of the SSL certificate file

cat /etc/ssl/certs/dhparam.pem | tee -a /etc/ssl/certs/ssl.crt

Let’s now configure the VirtualHost (to bind the certificate with our web app):

(I’ve previously created the file: beyondbaremetal.com.conf on that path)

nano /etc/httpd/conf.d/beyondbaremetal.com.conf

And set up as follows:

Finally, we can restart the Apache service:

systemctl restart httpd

We can open our web app at https://10.100.100.11:

We can verify it has the SSL certificate that we generated and bonded it to the web app:

Setting up DNS:

Now we have another challenge, the staff can’t remember which IP to use and they want to have a hostname instead: hr.beyondbaremetal.com, let’s configure that internally:

Let’s first log to the Domain Controller (DC) and create a new primary zone: beyondbaremetal.com

NOTE: When the website is live: beyondbaremetal.com we will need to come back here and add an A record for the website.

Open Server Manager > DNS

Right-click on Forward Lookup Zones > New Zone > Primary Zone

To all DNS servers running on domain controllers in this domain: beyondbaremetal.local

Zone name: beyondbaremetal.com

Allow only secure dynamic updates (recommended for Active Directory)

Review and finish:

Now go to the newly created zone: beyondbaremetal.com

Right-click on the main pane, select New host (A or AAAA) and set up as follows:

Go back to the main pane, right click and select now New Alias (CNAME), set up as follows:

Now we can check from a computer:

Notice we can open and verify is using the self-signed certificate:

SSL certificate with Active Directory Certificate Services

As you saw on the previous screens, whenever we access our web app it shows Not secure, even though we bonded an SSL certificate, that happens because that’s a self-signed certificate (not issued by any Certificate Authority), let’s now set up our Certificate Authority server and issue an SSL certificate.

Let’s login to BBM-DC01, Server manager > Manage > Add Roles and Features

Next

Select Role-based or featured-based installation, Next

Select Select a server from the server pool

Select and check Active Directory Certificate Services

Select Add Features

Check Certificate Authority

Finally we can hit Install:

We verify the install is complete:

Now let’s configure the Active Directory Certificate Services:

For role servers check Certificate Authority

Select Standalone CA

for CA type, select Root CA

Private key: Create a new private key

Cryptography:

  • Cryptographic provider: RSA#Microsoft Software Key Storage Provider

  • Key length: 2048

  • Hash algorithm: SHA256

CA Name: Leave a default

Validity Period: 5 Years

Certificate Database: leave as default

Review and hit Configure:

Now let’s go to Certificate Authority

We can check that we have the following:

  • Revoked Certificates

  • Issued Certificates

  • Pending Requests

  • Failed Requests

Let’s enable now Certificate Authority Web Enrollment:

Configure:

Configuration complete:

Now let’s go to our CentOS VM (Where Apache is running) and go to: 10.100.100.10/certsrv and select Request a certificate:

Advanced certificate request:

Now let’s create the Certificate Request (CSR):

openssl req -new -newkey rsa:2048 -nodes \
-keyout /etc/ssl/private/apache.key \
-out request.csr \
-subj "/C=US/ST=State/L=City/O=Organization/CN=hr.beyondbaremetal.com"

The result we copy and paste it on the request page:

After that we see that the Certificate is pending for approval:

Let’s go back to BBM-DC01 and open the Certification Authority tool > Pending Requests > Right click on the certificate and select All tasks > Issue

Next, we can see on the Issued Certificates, that the certificate has been issued correctly:

Let’s open it and export it:

Select Copy to File

Next:

Select the store for the cert in our case it will be: C:\SSL\hr.beyondbaremetal.com

Export complete:

After that let’s transfer it to our Web server BBM-WEB01:

Then let’s bind it our Virtual Host / Web app:

Then we can restart the Apache service (httpd)

Then let’s create a GPO to deploy the newly created Certificate to our domain-joined computers automatically:

Go to Computer Configuration > Policies > Windows Settings > Security Settings > Public Key > Trusted Root Certification Authorities right click and select Import

Next:

Select the Certificate:

Next:

Place all certificates in the following store: Trusted Root Certification Authorities and select Next

Finish

Import successful:

We can open it now on a domain joined computer and see the certificate is showing up correctly:

NOTE: It still shows Not Secure, which will be fixed later.

External Access

The previous was to make the Web app available for the internal network devices, but what about if we need it to be external facing in a secure way?

For that, we will use Cloudflare tunnels:

Let’s navigate to: https://one.dash.cloudflare.com/

Select Tunnels:

Set name and select the environment, for our case Red Hat:

We will be provided with a script to run on our Web server:

Then set up the public Hostname, (BBM-WEB01 private IP)

With that the Tunnel is all set:

After that, we can access the website externally and the SSL Certificate will be handled by CloudFlare:

Conclusion

We successfully set up a secure HR web application on a CentOS virtual machine using Apache in this implementation. We established multiple layers of security by implementing both a self-signed SSL certificate and later upgrading to an Active Directory Certificate Services-issued certificate. A domain controller enhanced The infrastructure with proper DNS configuration, allowing internal access via hr.beyondbaremetal.com. Finally, we enabled secure external access using Cloudflare tunnels, which provided an additional layer of security and SSL certificate management for public access. This setup ensures internal and external users can securely access the HR application while maintaining proper security protocols.

Thanks for reading!

Stay tuned for more content.

Link to the series 👉 beyondbaremetal.hashnode.dev/series/beyond-..