Add a Static Subdomain to a WordPress Server: Apache, Certbot and Validation

Static subdomain: two sites and folders connected to a shared server

Sometimes you need to run a static web app alongside WordPress on the same server. Maybe a WordPress cache plugin (FlyingPress, WP Rocket) is interfering with your JavaScript app, or you simply want zero WordPress dependency.

The goal is to serve a static subdomain from a DocumentRoot separate from the WordPress application. The sites still share the Apache process and server resources; VHost or certificate configuration changes and service restarts can affect the existing WordPress site.

Target architecture

xxx.xxx.xxx.xxx — Apache 2.4.37
www.datainhands.com
▸ via OCI WAF
▸ /var/www/html/wordpress
▸ SSL: WAF certificate
studio.datainhands.com
▸ Direct A record
▸ /var/www/studio
▸ SSL: certbot (verify renewal scheduling)

WAF bypass vs WAF passthrough

Review the new subdomain route together with the existing WordPress origin access boundary. Static content or avoidance of a WordPress cache plugin does not by itself make direct access safe. The table below lists options to review, not recommendations to apply automatically.

Before allowing direct access, separately authorize a review of whether other Host/SNI values on the same IP can reach WordPress, including the default VHost and origin restrictions. A 200/403 response to an IP request, a Server header or a DNS name alone does not prove WAF traversal, bypass prevention or correct TLS validation. -k skips certificate verification and is not evidence of a secure connection. This guide does not establish whether the current server permits a WAF bypass.

ScenarioRoute to reviewWhy
Static HTML, no sensitive dataDirect A recordcertbot; renewal scheduling needs verification
Dynamic app, security requiredWAF passthrough (CNAME)DDoS protection, bot filtering
Escaping cache plugin interferenceDirect A recordSeparate WordPress request handling (server resources remain shared)

Prerequisites: Apache port 80 listening

Apache Listen configures the addresses and ports where the service accepts connections; it is not a firewall rule. Direct HTTPS does not always require port 80. If HTTP service or an HTTP-01 validation path is needed, design port-80 reachability separately. The port-opening/restart examples below are not a sequence to run automatically. Review the actual VNIC security lists and NSGs, host firewall and existing WordPress protection boundary before deciding the minimum required access.

# Check Apache listening ports
sudo ss -tlnp | grep -E ":80 |:443 "
# Only 443? Need to enable 80

# Uncomment Listen 80
sudo sed -i 's/^#Listen 80$/Listen 80/' /etc/httpd/conf/httpd.conf
sudo apachectl configtest && sudo systemctl restart httpd
💡 OCI network rules: If HTTP service or HTTP-01 validation requires port 80, match the necessary source and destination ports against the Security Lists and NSGs applied to the actual VNIC. For TCP ingress, Destination Port Range identifies the receiving service port; Source Port Range identifies the sender’s port. Do not allow all sources (0.0.0.0/0) by default: decide access according to the service/validation path and existing origin protection boundary.

Deployment: 6 steps

1
DNS A record

Add studio A record → server IP, TTL 300.

dig studio.yourdomain.com @8.8.8.8 +short
# <your-server-ip>
2
DocumentRoot + HTTP VHost
sudo mkdir -p /var/www/studio
echo "<h1>studio OK</h1>" | sudo tee /var/www/studio/index.html
sudo chown -R apache:apache /var/www/studio

sudo tee /etc/httpd/conf.d/studio.conf << 'EOF'
<VirtualHost *:80>
    ServerName studio.yourdomain.com
    DocumentRoot /var/www/studio
    <Directory /var/www/studio>
        Require all granted
    </Directory>
</VirtualHost>
EOF

sudo apachectl configtest && sudo systemctl reload httpd
3
Example certbot SSL issuance command
sudo certbot --apache -d studio.yourdomain.com

The Apache plugin supports certificate issuance and installation; HTTPS and redirect changes depend on options and existing configuration. Automatic renewal scheduling depends on separate setup, such as cron or a systemd timer supplied by the installation method; this issuance command alone does not establish that scheduling is registered or running. Scheduled checks do not replace a certificate on every run. renew --dry-run tests renewal rather than renewing the live certificate, and can trigger webserver reloads and pre/post hooks. Deploy hooks normally run after successful live renewal and do not run in a dry-run without an additional option. Reloading to serve a renewed certificate depends on installer/hooks and service configuration. This article is not a verification record of the current server’s scheduler, hooks or reload behavior.

4
VHost hardening (security headers + caching)

Conditions for this cache example: The one-year immutable setting below applies only to URLs whose content stays unchanged throughout their freshness lifetime. Do not apply it unchanged to this guide's same-filename overwrite deployment. Consider long-lived caching only when assets receive new content-hashed or versioned URLs and their HTML references are updated together.

Design a separate revalidation policy for HTML and files updated at the same URL. For example, no-cache requires validation before reuse; it does not prohibit storage. Changing server headers or purging a CDN may not immediately reclaim fresh immutable responses already in browsers. Decide header precedence and deployment/recovery behavior after reviewing the environment.

# Add to studio-le-ssl.conf
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Strict-Transport-Security "max-age=63072000"

# Static assets: 1-year cache
<FilesMatch "\.(js|css|png|jpg|svg|woff2?)$">
    Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>

# Gzip compression
AddOutputFilterByType DEFLATE text/html text/css application/javascript
5
Deploy app files
sudo cp -r studio-files/* /var/www/studio/
sudo chown -R apache:apache /var/www/studio/
6
Verify

The header requests below illustrate response checks. The code comment “Original site unaffected” is not established by these requests alone. HTTP 200 does not guarantee existing-site functionality, performance or impact-free deployment and recovery.

curl -sI https://studio.yourdomain.com | grep -E "HTTP|X-|Strict|Cache"
# HTTP/1.1 200 OK + security headers + cache headers

# Original site unaffected
curl -sI https://yourdomain.com | head -3

WordPress plugin → standalone HTML conversion

If your JS app reads config via wp_localize_script:

// JS expects this global
const cfg = window.PatternStudioConfig || {};
// The || {} fallback means: no JS modifications needed

|| {} falls back to an empty object when configuration is absent; it does not establish that the app works without WordPress. First check REST/Ajax calls, nonces and authentication, server data and other plugin dependencies. The configuration below is an example for an app without those external dependencies that supports this configuration format. Consider wp_add_inline_script for passing general configuration data.

<script>
window.PatternStudioConfig = {
  version: '2.5.3',
  persistInput: false,
  locale: navigator.language,
  ai: { enabled: false }
};
</script>
<script src="assets/js/app.js"></script>
✅ Scope of separation: Static files served directly by a separate VHost and DocumentRoot bypass WordPress application request handling. The cache and optimization rules actually applied still require separate verification; shared Apache configuration and server resources are not isolated.

Rollback

Removing VHost files does not restore every pre-deployment state. The deletion/restart example below is not a complete rollback procedure and must not be run unchanged. WordPress can also be affected because it shares the Apache process.

Before deployment, record prior values, backups and recovery order for each changed item: DNS records and proxy routing, Apache VHosts and shared Listen settings, network and host firewalls, deployed files and ownership, certificate references and Certbot renewal configuration. Do not include private-key contents in that record.

During recovery, limit restoration to changes from this deployment and check dependencies of other services. Back up and disable the VHost, check configuration syntax, choose reload/graceful or restart as appropriate for the environment, and verify both WordPress and the new subdomain. Removing a VHost does not automatically clean up certificates or renewal configuration; recovery cannot be declared complete before DNS/cache propagation is accounted for.

Illustrative example — do not execute. These two lines omit backup, dependency checks, syntax validation and stopping on failure. The first deletes VHost files; the second is an Apache restart command that is not conditionally chained to the first line’s success. Copying and running this block cannot substitute for the recovery procedure above.

sudo rm /etc/httpd/conf.d/studio.conf /etc/httpd/conf.d/studio-le-ssl.conf
sudo systemctl restart httpd
Scroll to Top