Learn how to achieve perfect scores for website security, performance and SEO using AWS S3 and CloudFront, plus some of the gotchas. This article shows real-world examples achieving A+ SSL Labs, 100% PageSpeed and 120/100 Mozilla Observatory scores. I hope you find it useful.
Last Updated: 2nd October 2025 Author: Chris Binnie, cybersecurity consultant, author & writer
Achieving enterprise-level website security, performance and SEO scores is not only possible but somewhat surprisingly it’s really cost-effective. The information in this guide was hard-won and demonstrates how to build websites that achieve:
⚠️ Important: The code examples and configurations in this guide are only for reference. Improper configuration of security headers, CloudFront Functions or AWS services can cause downtime or introduce security vulnerabilities. Use the information in this article at your own risk; you have been suitably warned!
This page focuses on two real-world examples (chrisbinnie.com and chrisbinnie.co.uk) and following some unwelcome eyestrain shares the architecture, configuration and implementation strategies that deliver enterprise-level results whilst maintaining costs of only around $1-$2 monthly (excluding annual Domain Name fees).
Modern websites face a challenging paradox: it’s really tricky to get it right. Users demand instant loading times and seamless experiences, whilst security threats grow increasingly sophisticated. Search engines prioritise both security and performance in their ranking algorithms, making these three pillars—security, performance and SEO—fundamentally interconnected.
Most websites struggle to achieve excellence across all three domains because they:
The solution lies in architectural simplicity: static sites with modern security headers, global content delivery and zero dependencies.
Security encompasses protecting your website and users from threats including cross-site scripting (XSS), clickjacking, man-in-the-middle attacks and data breaches. Perfect security requires properly configured TLS/SSL, comprehensive HTTP security headers and minimal attack surface.
Performance measures how quickly your website loads and becomes interactive. Core Web Vitals—Largest Contentful Paint (LCP), First Input Delay (FID) and Cumulative Layout Shift (CLS)—directly impact user experience and search rankings.
SEO (Search Engine Optimisation) determines your website’s visibility in search results. Technical SEO requires fast loading times, mobile optimisation, proper schema markup and secure connections—all factors that overlap with security and performance.
Static websites represent the optimal architecture for achieving perfect security, performance and SEO scores. Unlike dynamic sites requiring server-side processing, databases and complex application logic, static sites serve pre-rendered HTML, CSS and JavaScript files directly to users. The factors influencing the design were firstly to avoid absolutely all library dependencies (to stop the ever-growing number of supply chain attacks) and secondly show some simple functionality, but keep any javascript or CSS as secure and clean as possible. It was frustrating at times but after the initial headaches the sites work well in most browsers and on both mobiles and desktops.
Security Benefits:
Performance Benefits:
SEO Benefits:
Static sites excel for:
Static sites may not suit:
Amazon Web Services provides the ideal infrastructure for hosting secure, performant static websites through S3 (Simple Storage Service) for storage and CloudFront for global content delivery. The main reason for choosing AWS was the excellent performance and the DDoS protection that CloudFront offers.
Create an S3 bucket with these essential settings:
# Create S3 bucket (replace with your domain)
aws s3 mb s3://www.your-domain.com --region us-east-1
# Enable versioning for backup and recovery
aws s3api put-bucket-versioning \
--bucket www.your-domain.com \
--versioning-configuration Status=Enabled
# Enable server-side encryption
aws s3api put-bucket-encryption \
--bucket www.your-domain.com \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# Configure bucket policy for CloudFront access
cat > bucket-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCloudFrontAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity YOUR-OAI-ID"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.your-domain.com/*"
}]
}
EOF
aws s3api put-bucket-policy \
--bucket www.your-domain.com \
--policy file://bucket-policy.json
Achieving perfect performance scores requires attention to every aspect of page delivery, from initial request to final render.
Create minimal, semantic HTML:
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Expert cybersecurity guidance and Linux server security resources">
<title>Linux Server Security | Chris Binnie</title>
<!-- Preconnect to improve performance -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<!-- Critical CSS inline -->
<style>
/* Critical above-the-fold styles */
body { margin: 0; font-family: system-ui, sans-serif; }
header { background: #1a1a1a; color: #fff; padding: 1rem; }
</style>
<!-- Defer non-critical CSS -->
<link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
<!-- Favicon -->
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
</head>
<body>
<header>
<h1>Linux Server Security</h1>
</header>
<main>
<!-- Content here -->
</main>
<!-- Defer JavaScript -->
<script src="/script.js" defer></script>
</body>
</html>
Key optimisations:
defer
attributeWrite efficient, minimal CSS:
/* Use modern CSS features */
:root {
--primary-colour: #0066cc;
--spacing: 1rem;
}
/* Mobile-first responsive design */
body {
font-size: clamp(1rem, 2.5vw, 1.125rem);
line-height: 1.6;
max-width: 70ch;
margin: 0 auto;
padding: var(--spacing);
}
/* Efficient selectors */
.container {
display: grid;
gap: var(--spacing);
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
/* Hardware-accelerated animations */
.fade-in {
animation: fadeIn 0.3s ease-in;
will-change: opacity;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Performance principles:
will-change
for animated elementsWrite performant vanilla JavaScript:
// Use modern JavaScript features
const initApp = () => {
// Efficient DOM queries
const elements = {
nav: document.querySelector('nav'),
main: document.querySelector('main')
};
// Debounced scroll handler
let ticking = false;
const handleScroll = () => {
if (!ticking) {
window.requestAnimationFrame(() => {
// Scroll logic here
ticking = false;
});
ticking = true;
}
};
// Passive event listeners
window.addEventListener('scroll', handleScroll, { passive: true });
// Intersection Observer for lazy loading
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
};
// Execute when DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initApp);
} else {
initApp();
}
JavaScript best practices:
requestAnimationFrame
for smooth animationsImplement modern image formats and techniques (this route wasn’t used, choosing heavily optimised JPGs instead):
<!-- Responsive images with modern formats -->
<picture>
<source
srcset="/images/hero.avif"
type="image/avif">
<source
srcset="/images/hero.webp"
type="image/webp">
<img
src="/images/hero.jpg"
alt="Linux server security"
width="1200"
height="630"
loading="lazy"
decoding="async">
</picture>
Image guidelines:
loading="lazy"
for below-the-fold imagessrcset
Enable CloudFront compression for text resources:
# Configure compression in CloudFront distribution
aws cloudfront update-distribution \
--id YOUR-DISTRIBUTION-ID \
--distribution-config '{
"DefaultCacheBehavior": {
"Compress": true,
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6"
}
}'
CloudFront automatically compresses:
Compression reduces file sizes by 70-90% for text-based resources. It’s a real eye-opener if you do some Brotli and gzip compression tests. In my experience it makes a big difference to the browsing UX.
Perfect SEO requires both a technical implementation and content strategy. This section focuses on both technical SEO foundations.
Implement JSON-LD structured data:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Linux Server Security",
"url": "https://www.chrisbinnie.com",
"author": {
"@type": "Person",
"name": "Chris Binnie",
"url": "https://www.chrisbinnie.com",
"sameAs": [
"https://www.linkedin.com/in/chrisbinnie",
"https://github.com/chrisbinnie"
]
},
"description": "Expert Linux server security guidance and cybersecurity resources",
"inLanguage": "en-GB"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Complete Linux Server Security Guide",
"author": {
"@type": "Person",
"name": "Chris Binnie"
},
"datePublished": "2025-10-01",
"dateModified": "2025-10-01",
"image": "https://www.chrisbinnie.com/images/linux-security.jpg"
}
</script>
Implement comprehensive meta tags:
<!-- Primary Meta Tags -->
<title>Linux Server Security: Complete Hardening Guide | Chris Binnie</title>
<meta name="title" content="Linux Server Security: Complete Hardening Guide">
<meta name="description" content="Expert Linux server security guidance covering Ubuntu, CentOS, Debian hardening, intrusion detection and defence strategies.">
<meta name="keywords" content="linux security, server hardening, ubuntu security, centos security">
<meta name="author" content="Chris Binnie">
<link rel="canonical" href="https://www.chrisbinnie.com/linux-server-security">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://www.chrisbinnie.com/linux-server-security">
<meta property="og:title" content="Linux Server Security: Complete Hardening Guide">
<meta property="og:description" content="Expert Linux server security guidance covering Ubuntu, CentOS, Debian hardening, intrusion detection and defence strategies.">
<meta property="og:image" content="https://www.chrisbinnie.com/images/og-image.jpg">
<meta property="og:locale" content="en_GB">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://www.chrisbinnie.com/linux-server-security">
<meta property="twitter:title" content="Linux Server Security: Complete Hardening Guide">
<meta property="twitter:description" content="Expert Linux server security guidance covering Ubuntu, CentOS, Debian hardening, intrusion detection and defence strategies.">
<meta property="twitter:image" content="https://www.chrisbinnie.com/images/twitter-image.jpg">
Generate and submit an XML sitemap:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.chrisbinnie.com/</loc>
<lastmod>2025-10-01</lastmod>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://www.chrisbinnie.com/linux-server-security</loc>
<lastmod>2025-10-01</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
Submit to search engines:
Get the basics right and make sure that you create a proper robots.txt file:
User-agent: *
Allow: /
Sitemap: https://www.chrisbinnie.com/sitemap.xml
# Block specific paths if needed
Disallow: /private/
Disallow: /admin/
Despite it being a single-page website, it boasts enterprise-level SEO, performance and security:
Architecture:
Content:
Test Results:
+-----------------------------------+
| SSL Labs (Qualys) Rating |
| |
| A+ |
| |
| o Certificate |
| o Protocol Support |
| o Key Exchange |
| o Cipher Strength |
+-----------------------------------+
+-----------------------------------+
| Mozilla HTTP Observatory |
| |
| A+ 120/100 |
| |
| Tests Passed: 10 / 10 |
+-----------------------------------+
+-----------------------------------+
| Google PageSpeed Insights |
| |
| Performance: 100 |
| Accessibility: 96 |
| Best Practices: 100 |
| SEO: 100 |
| |
| (Both Mobile & Desktop) |
+-----------------------------------+
Security Headers Implemented:
$ curl -I https://www.chrisbinnie.com
HTTP/2 200
content-type: text/html
content-length: 22811
server: AmazonS3
via: 1.1 220eccae845bbee6b6bb000837ec3cd0.cloudfront.net (CloudFront)
x-amz-server-side-encryption: AES256
# Security Headers
strict-transport-security: max-age=31536000; includeSubDomains; preload
content-security-policy: default-src 'self'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data: https:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests; require-trusted-types-for 'script'
x-frame-options: DENY
x-content-type-options: nosniff
x-xss-protection: 1
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
cross-origin-opener-policy: same-origin
cross-origin-resource-policy: same-origin
# Caching
cache-control: public, max-age=60, must-revalidate
x-cache: Hit from cloudfront
(Very) Rough Estimated Monthly Costs:
AWS Services (estimated):
├── S3 Storage (1 GB): $0.023
├── S3 Requests (10,000): $0.01
├── CloudFront Data Transfer (5 GB): $0.50
├── CloudFront Requests (50,000): $0.06
├── CloudFront Functions: $0.01
└── ACM Certificate: $0.00 (free)
-------
Total Monthly Cost: $0.60
With moderate traffic (50K requests): $1-$2/month
Additional Site: The chrisbinnie.co.uk domain achieves identical security and performance scores using the same architecture and security header configuration.
Key Insight: Perfect scores across all testing platforms achieved with minimal infrastructure cost and zero dependencies. Total page weight of 22.8 KB enables instant loading globally via CloudFront edge caching.
Maintaining perfect scores requires some ongoing attention, but thankfully not too much! Static sites demand minimal maintenance compared to traditional platforms and should be relatively painless to run.
Implement automated security checks:
#!/bin/bash
# monthly-security-audit.sh
DOMAIN="www.chrisbinnie.com"
DATE=$(date +%Y-%m-%d)
REPORT_DIR="./security-reports"
mkdir -p "$REPORT_DIR"
echo "Running security audit for $DOMAIN on $DATE"
# Check SSL Labs grade
echo "Checking SSL configuration..."
curl -s "https://api.ssllabs.com/api/v3/analyze?host=$DOMAIN" > "$REPORT_DIR/ssllabs-$DATE.json"
# Check security headers
echo "Checking security headers..."
curl -sI "https://$DOMAIN" > "$REPORT_DIR/headers-$DATE.txt"
# Check for mixed content
echo "Scanning for mixed content..."
wget --spider --recursive --level=2 "https://$DOMAIN" 2>&1 | grep "http://" > "$REPORT_DIR/mixed-content-$DATE.txt"
# Check certificate expiry
echo "Checking certificate expiry..."
echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null | openssl x509 -noout -dates > "$REPORT_DIR/cert-expiry-$DATE.txt"
echo "Security audit complete. Reports saved to $REPORT_DIR"
Set up continuous performance monitoring using this simple script, alter it in any way that helps. Even just logging the history of scores periodically can help make historical comparisons if something breaks.
#!/bin/bash
# performance-monitor.sh
DOMAIN="www.chrisbinnie.com"
LIGHTHOUSE_API_KEY="your-api-key"
# Run Lighthouse audit
curl -X POST \
"https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://$DOMAIN&strategy=mobile&key=$LIGHTHOUSE_API_KEY" \
-o lighthouse-report.json
# Parse results
PERFORMANCE=$(jq '.lighthouseResult.categories.performance.score * 100' lighthouse-report.json)
ACCESSIBILITY=$(jq '.lighthouseResult.categories.accessibility.score * 100' lighthouse-report.json)
SEO=$(jq '.lighthouseResult.categories.seo.score * 100' lighthouse-report.json)
echo "Performance: $PERFORMANCE%"
echo "Accessibility: $ACCESSIBILITY%"
echo "SEO: $SEO%"
# Alert if scores drop below 95%
if (( $(echo "$PERFORMANCE < 95" | bc -l) )); then
echo "ALERT: Performance score dropped below 95%" | mail -s "Performance Alert" admin@example.com
fi
Static sites require minimal updates:
Monthly tasks:
Quarterly tasks:
Annual tasks:
Implement efficient content updates:
#!/bin/bash
# deploy.sh - Simple deployment script
BUCKET="s3://www.chrisbinnie.com"
DISTRIBUTION_ID="YOUR-DISTRIBUTION-ID"
echo "Starting deployment..."
# Sync files to S3 with appropriate cache headers
aws s3 sync ./public/ $BUCKET \
--delete \
--cache-control "public, max-age=31536000, immutable" \
--exclude "*.html" \
--exclude "sitemap.xml" \
--exclude "robots.txt"
# HTML files with shorter cache
aws s3 sync ./public/ $BUCKET \
--delete \
--cache-control "public, max-age=3600, must-revalidate" \
--exclude "*" \
--include "*.html" \
--include "sitemap.xml" \
--include "robots.txt"
# Invalidate CloudFront cache for updated content
aws cloudfront create-invalidation \
--distribution-id $DISTRIBUTION_ID \
--paths "/*"
echo "Deployment complete!"
In my experience achieving perfect website security, performance and SEO scores is entirely achievable through architectural simplicity, comprehensive security headers and modern hosting infrastructure. The examples of chrisbinnie.com and chrisbinnie.co.uk demonstrate that professional results don’t require complex solutions or significant investment.
Architecture:
Security:
Performance:
SEO:
Phase 1: Starter For Ten
Phase 2: Security
Phase 3: Performance
Phase 4: SEO
Phase 5: Monitoring
Track these metrics monthly:
Security Metrics:
Performance Metrics:
Business Metrics:
Official Documentation:
Testing Tools:
Books by Chris Binnie:
Community Resources:
The journey to perfect website security, performance and SEO scores begins with architectural decisions. By choosing static site hosting on AWS S3 and CloudFront, implementing comprehensive security headers through CloudFront Functions and optimising every aspect of content delivery, you can achieve enterprise-level professional results—for monthly costs of $1-$2.
The real-world examples presented demonstrate that these aren’t theoretical ideals but practical, proven architectures delivering exceptional results in production environments. With total monthly costs under $2, zero dependencies to maintain and perfect scores across all testing platforms, this approach represents the optimal balance of security, performance, cost and maintenance overhead.
Whether building a personal portfolio, company website or documentation platform, these principles and implementation strategies provide a roadmap to excellence. Start with the foundation, implement security comprehensively, optimise performance relentlessly and maintain your infrastructure diligently. The result will be a website that excels in every measurable metric whilst requiring minimal ongoing attention and delivering enterprise-level performance.
Explore these comprehensive guides for deeper insights into specific topics:
About the Author
Chris Binnie is a cybersecurity consultant and author with nearly thirty years of experience in information security. He has authored multiple cybersecurity books including Cloud Native Security (co-authored with Rory McCune), Linux Server Security: Hack and Defend and Practical Linux Topics. Based in Edinburgh, Scotland, Chris has been a regular contributor to Linux Magazine and ADMIN Magazine for around 15 years. His practical experience includes founding a colocation business in 2001 to achieve zero downtime through redundant infrastructure and designing cloud-based streaming platforms serving HD video to 77 countries in 2012.
⚠️ Important: All information in this guide is provided for reference purposes only and should be treated as untested! Before implementing any of these configurations on production systems, thoroughly test them in development environments. Use the information at your own risk.