πŸ” Building a Secure Web Application Stack with Apache, PostgreSQL, Keycloak, and Firewalld

Praneeth PereraPraneeth Perera
4 min read

πŸ“Œ Introduction

In today’s cloud-native environments, application security is more than just HTTPS. Strong authentication, network segmentation, encryption, and access control are all critical to protecting infrastructure.

This article walks through the end-to-end setup of a secure Linux-based application stack:

  • A jump host for controlled SSH access

  • An application host running Apache, PHP, PostgreSQL, and Keycloak

  • Let’s Encrypt SSL for secure HTTPS with automatic redirects

  • OIDC authentication with Keycloak to protect the web app

  • TOR exit node blocking using firewalld + ipset

  • Audit and SSH hardening for compliance

The project demonstrates how to combine system administration, DevOps, and security best practices into a cohesive solution.


πŸ—οΈ Architecture

  • Jump Host: The only public SSH entry point.

  • App Host: Runs Apache, a PHP app, a PostgreSQL database, and Keycloak.

  • DNS + Let’s Encrypt: Provides valid SSL/TLS certificates.

  • Firewalld + ipset: Drops all HTTP/HTTPS requests from TOR exit nodes.


πŸ” Authentication Flow

  1. User visits https://demo.example.com.

  2. Apache’s mod_auth_openidc detects that the site is protected and redirects to Keycloak.

  3. User authenticates against Keycloak Realm: demo.

  4. Keycloak returns an authorisation code to Apache.

  5. Apache exchanges it for tokens, sets a secure session, and forwards the user back to the PHP app.

This ensures all application access goes through Keycloak authentication.


πŸ›‘οΈ Blocking TOR Exit Nodes

  • TOR exit IPs are downloaded every 30 minutes from torproject.org.

  • Added to a firewalld ipset.

  • Rich rules drop any connection to ports 80/443 from those IPs.

  • All other traffic is allowed.

This reduces the attack surface by blocking anonymous traffic often used in brute-force or scraping attempts.


βš™οΈ Step-by-Step Implementation

Task 0 β€” Prerequisites

  • Two Linux VMs: Jump Host & App Host.

  • DNS records:

    • demo.example.com β†’ App host IP

    • keycloak.example.com β†’ App host IP

  • SSH keypair for secure login.


Task 1 β€” OS Hardening

  • Create a non-root sudo user.

  • Disable root login & password authentication in sshd_config.

  • Enable auditd activity logging.

  • Extend shell history with timestamps.


Task 2 β€” SSH Restriction

  • Configure firewalld to allow SSH on the App host only from the Jump host IP.

  • Users must hop through Jump β†’ App.


Task 3 β€” Application Stack

  • Install Apache, PHP, and PostgreSQL.

  • Create database & user:

      CREATE USER appuser WITH PASSWORD 'StrongP@ss-ChangeMe';
      CREATE DATABASE appdb OWNER appuser;
    
  • Deploy a demo PHP app that queries PostgreSQL.


Task 4 β€” Keycloak Setup

  • Run Keycloak in Docker with PostgreSQL backend.

  • Reverse proxy via Apache at https://keycloak.example.com.

  • Admin user: admin / SetAdminPass.


Task 5 β€” HTTPS with Let’s Encrypt

  • Use Certbot with the Apache plugin:

      sudo certbot --apache -d demo.example.com -d keycloak.example.com --redirect
    
  • Enforce HTTPS and redirect from HTTP β†’ HTTPS.


Task 6 β€” Keycloak Realm & Client

  • Create Realm demo.

  • Add Client demo-app:

    • Redirect URI: https://demo.example.com/oidc/callback

    • Web origin: https://demo.example.com

  • Copy client secret for Apache config.

  • Create a test user testuser.


Task 7 β€” Protecting the App with OIDC

Apache vhost config (demo-ssl.conf):

OIDCProviderMetadataURL https://keycloak.example.com/realms/demo/.well-known/openid-configuration
OIDCClientID demo-app
OIDCClientSecret <client-secret>
OIDCRedirectURI https://demo.example.com/oidc/callback
OIDCCryptoPassphrase SomeRandomString

<Location />
   AuthType openid-connect
   Require valid-user
</Location>

Now, all requests require Keycloak login.


Task 8 β€” TOR Blocking with Firewalld

Script: tor-blocklist-refresh.sh

#!/usr/bin/env bash
set -euo pipefail
LOGFILE="/var/log/tor-blocklist.log"
TMP=$(mktemp)

{
  echo "[$(date '+%F %T')] Refreshing TOR blocklist..."
  curl -s https://check.torproject.org/exit-addresses | \
      awk '/^ExitAddress/ {print $2}' | sort -u > "$TMP"
  sudo firewall-cmd --permanent --delete-ipset=tor || true
  sudo firewall-cmd --permanent --new-ipset=tor --type=hash:ip
  while read -r ip; do
    sudo firewall-cmd --permanent --ipset=tor --add-entry="$ip"
  done < "$TMP"
  sudo firewall-cmd --reload
  rm -f "$TMP"
  echo "[$(date '+%F %T')] Done."
} >> "$LOGFILE" 2>&1

Cron job:

*/30 * * * * root /usr/local/bin/tor-blocklist-refresh.sh

Task 9 β€” Final Validation

βœ… Visiting http://demo.example.com β†’ Redirects to https://demo.example.com.
βœ… Redirected to Keycloak β†’ Login β†’ Back to demo app.
βœ… SSL certificates are valid.
βœ… SSH to App only works via Jump.
βœ… TOR traffic dropped.


πŸ“‚ Repository

All configs, scripts, and docs are available in the GitHub repo:
πŸ‘‰ secure-app-stack

secure-app-stack/
β”œβ”€β”€ README.md
β”œβ”€β”€ docs/ (setup-guide + diagrams)
β”œβ”€β”€ scripts/ (tor-blocklist-refresh.sh)
β”œβ”€β”€ apache/ (vhost configs + demo app)
└── sql/ (init scripts)

🏁 Conclusion

This project demonstrates how to combine Linux sysadmin, DevOps, and security practices into a single, secure stack:

  • Enforcing jump-host-only SSH

  • Using Keycloak for authentication

  • Enabling valid HTTPS with automatic redirects

  • Blocking TOR traffic at the firewall

  • Auditing and hardening the OS

It’s a real-world-ready blueprint for securing small applications or proving your DevOps skills in interviews.


0
Subscribe to my newsletter

Read articles from Praneeth Perera directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Praneeth Perera
Praneeth Perera

As a Senior System Administrator at NoeHow, I specialise in network analysis, troubleshooting, automation, and system migrations using Python, Perl, Bash, and MySQL. I'm passionate about training teams and staying current with emerging technologies to optimise system functionality and user experiences. With RHCE and AWS Certified Solutions Architect Associate certifications, a B.Sc. in Information Systems from the University of Colombo, an MBA from the University of Bedfordshire, and a strong accountancy background, I bring technical expertise and business acumen to every project. I thrive in collaborative environments and am eager to connect with innovative professionals.