Infrastructure diary: from frontend to DNS, fixing next.js, performance, and Bash automation issues
Back to blog

Infrastructure diary: from frontend to DNS, fixing next.js, performance, and Bash automation issues

6/7/2026 · 5 min · Development

Working in the trenches means your daily routine never stays within a single stack. In a matter of hours, you can go from debugging a frontend build configuration to optimizing media performance, and immediately after, running terminal loops to fix DNS zones manually.

In this post, I document three real technical battles recently faced and how I solved them, expanding the DNS infrastructure section to cover backups, BIND9 syntax checks, multilateral propagation, and security.


1. The next.js bundle analyzer nightmare with Bun and turbopack#

When trying to analyze bundle weight in a Next.js project using Bun as the runtime, the first attempt was to run the CLI directly:

bunx @next/bundle-analyzer

Error: could not determine executable to run.

The failure here is conceptual: @next/bundle-analyzer is not a standalone binary CLI tool; it is a configuration plugin for next.config.ts. It needs to intercept the Next.js compilation process to inject analysis hooks.

I adjusted next.config.ts to enable the plugin via an environment variable:

import type { NextConfig } from "next";
import withBundleAnalyzer from '@next/bundle-analyzer';

const configureBundleAnalyzer = withBundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
});

const nextConfig: NextConfig = {
  reactCompiler: true,
  turbopack: {}, // New Rust-based engine configuration
  // ... other headers and image configs
};

export default configureBundleAnalyzer(nextConfig);

When trying to run ANALYZE=true bun run build, I hit a new barrier: The current Bundle Analyzer is not compatible with Turbopack (the Webpack successor in Next.js 16+).

To bypass this and get the visual bundle report, I forced the build using Webpack via a flag, remembering to use -- to redirect arguments to the internal script:

ANALYZE=true bun run build -- --webpack

(Note: For those who prefer staying within the Rust ecosystem, the bunx next experimental-analyze command is the experimental native alternative for Turbopack).


2. Performance optimization: video tag vs animated webp#

In a project with strict payload requirements (target: 200kb per section), Lottie animations were consuming too much CPU due to JavaScript/DOM rendering. Attempting to convert to animated WebP resulted in a drastic loss of fluidity to stay within the size limit (reduced frames and artifacts).

I replaced animated images with the <video> tag configured to emulate image behavior:

<video
  autoPlay
  loop
  muted
  playsInline // Crucial to avoid automatic fullscreen overlay on iOS
  preload="auto"
  poster="/assets/poster-static.jpg" 
>
  <source src="/assets/animation.webm" type="video/webm" />
  <source src="/assets/animation.mp4" type="video/mp4" />
</video>

For complex vectors, the modern alternative would be Rive (.riv), but for rasterized or 3D elements, <video> remains undefeated in weight/performance ratio.


3. Planning DNS zone backups (finding #1 & #8)#

When dealing with bulk editing of DNS zones (BIND9), the first golden rule of a SysAdmin is to never edit zone files without a consistent backup. A typo in the script's regex can corrupt dozens of domains, breaking name resolution.

Create a temporary directory and generate a compressed copy of the files under /var/named/ before proceeding with any loop changes:

# Create a secure backup directory in root
mkdir -p /root/zones-backup/

# Complete backup of all .db files in tar.gz format
tar czf /root/zones-backup-$(date +%Y%m%d).tar.gz /var/named/*.db

# Timestamped backup for each individual zone file
for zone in $(cat domains.txt); do
    cp /var/named/$zone.db /root/zones-backup/$zone.db.$(date +%Y%m%d) 2>/dev/null
done

# Validate the size of the created backup directory
du -sh /root/zones-backup/

This guarantees an immediate rollback to the operational baseline state of DNS records.


4. BIND syntax validation (finding #3)#

The named daemon will reject entire zones if there are syntax errors in the records (e.g. missing dots at the end of FQDNs, malformed IPs, or broken SOA serials).

Use BIND's native binaries to check syntax before reloading:

# Validate global syntax of zones listed in the batch file
for zone in $(cat domains.txt); do
    echo "Checking zone integrity: $zone"
    named-checkzone $zone /var/named/$zone.db
done

# Check the syntactical consistency of the main configuration file
named-checkconf

If the output of the above command displays OK, the records are structured correctly for reload.


5. Post-alteration record verification (finding #2)#

With the regex changes applied, it is critical to perform logical tests to ensure that the zone loaded and that the SOA serials were incremented as planned.

# Validate if named accepted the updated domain structure
named-checkzone domain.com /var/named/domain.com.db

# Confirm if the SOA serial was updated to the current timestamp (10 digits)
grep -o '[0-9]\{10\}' /var/named/domain.com.db | head -1

# Verify the presence and new IP of the mail record
grep "mail" /var/named/domain.com.db

# Test the internal resolution of the record against the local DNS server
dig @localhost mail.domain.com A +short

# Test if the resolution returns the correct IP using the external resolver
dig @8.8.8.8 mail.domain.com A +short

6. DNS security auditing and hardening (finding #9)#

An open DNS server can be exploited for DNS amplification attacks or leaking internal network topology. Basic hardening involves restricting zone transfers (AXFR) to authorized IPs in ACLs in /etc/named.conf:

# Check for unprotected allow-transfer directives in named.conf
named-checkconf | grep -i "allow-transfer"

# Audit the main configuration looking for restrictions
grep -i "allow-transfer" /etc/named.conf

# Verify the declaration of authorized Access Control Lists (ACLs)
grep -i "acl" /etc/named.conf

Make sure to configure allow-transfer { none; }; or restrict to authorized secondary DNS servers IPs.


7. Advanced BIND logs diagnostics (finding #4 & #7)#

Zone rejection events or timeouts must be analyzed in logs in real time to diagnose sync failures (Split Brain):

# Tailing errors and warnings in named logs
tail -50 /var/log/named.log
grep -i -E "error|warning" /var/log/named.log | tail -20

# Check specific DNS query logs in real time (if enabled)
tail -20 /var/log/named/query.log

# Query the general operational status of the daemon
rndc status

# Query individual load status of a specific zone
rndc zonestatus domain.com

8. Auditing the scope of other zones (finding #5)#

When automating changes with scripts, orphan zones or unplanned domains might end up with inconsistent records. It is prudent to check the serials of all zones predictively to find obsolete configurations:

# List all active zone bases on the server
ls -la /var/named/*.db

# Query and display the serial of all registered zones
for zone in /var/named/*.db; do
    echo "$(basename $zone): $(grep -o '[0-9]\{10\}' $zone | head -1)"
done

# Alert: Detect zones with serials older than a cutoff date (e.g. before 2026)
for zone in /var/named/*.db; do
    SERIAL=$(grep -o '[0-9]\{10\}' $zone | head -1)
    if [ ! -z "$SERIAL" ] && [ "$SERIAL" -lt "2026010100" ]; then
        echo "ALERT: Obsolete serial detected in $zone: $SERIAL"
    fi
done

9. Multilateral propagation verification (finding #6)#

Changing DNS on the local authoritative server does not mean immediate access to the outside world due to TTL (Time to Live) caching. Perform multilateral checks against popular public DNS resolvers:

# Check response across multiple popular public DNS recursive servers
for dns in 8.8.8.8 1.1.1.1 208.67.222.222; do
    echo "Querying DNS $dns: $(dig @$dns mail.domain.com A +short)"
done

# Audit remaining TTL of the record
dig mail.domain.com A | grep -A1 "ANSWER SECTION"

# Ensure the old IP does not appear in the query
dig @8.8.8.8 mail.domain.com A +short

10. Script automation and cron (finding #10)#

To maintain long-term server compliance and avoid human syntactic errors, we package the zone editing workflow into a robust production modular shell script at /usr/local/bin/update-dns-serial.sh:

# Inject the secure automation script
cat > /usr/local/bin/update-dns-serial.sh << 'EOF'
#!/bin/bash
# Secure automation script for BIND9 SOA serial updates
set -euo pipefail

NEW_SERIAL=$(date +%Y%m%d%H)
ZONES_FILE="/etc/zones.txt"

if [ ! -f "$ZONES_FILE" ]; then
    echo "Error: Domains list file ($ZONES_FILE) not found." >&2
    exit 1
fi

# Preventive backup before execution
tar czf /root/zones-cron-backup-$(date +%Y%m%d).tar.gz /var/named/*.db

for domain in $(cat "$ZONES_FILE"); do
    db_file="/var/named/$domain.db"
    if [ -f "$db_file" ]; then
        OLD_SERIAL=$(grep -o '[0-9]\{10\}' "$db_file" | head -n 1)
        if [ ! -z "$OLD_SERIAL" ]; then
            # Update serial
            sed -i "s/$OLD_SERIAL/$NEW_SERIAL/" "$db_file"
            
            # Remove old A record and inject updated one
            sed -i "/^mail/d" "$db_file"
            echo "mail IN A 203.0.113.50" >> "$db_file"
            
            # Local syntax check
            named-checkzone "$domain" "$db_file" >/dev/null
        fi
    fi
done

# Reload BIND configurations
rndc reload
echo "DNS configurations reloaded successfully in BIND!"
EOF

# Strict execution permissions
chmod 755 /usr/local/bin/update-dns-serial.sh

You can schedule the script to run periodically in the system cron (e.g., daily at 2:00 AM):

# Add cron rule to root crontab
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/update-dns-serial.sh") | crontab -

11. DNS automation checklist#

Below is the operational checklist for manipulating and validating BIND DNS zones:

Phase 1: Planning & backup#

Phase 2: Rules execution#

Phase 3: Reload & propagation#


12. Risk and mitigation matrix#

Item / RiskSeverityTechnical DescriptionMitigation Measure
Invalid Zone (Crash)HighA corrupted .db file or missing serial causes named to drop the zone, taking down the domain.Always run named-checkzone in loops before reload. Keep preventive backups active.
Out-of-Sync (Split Brain)HighFailure to increment the SOA Serial prevents secondary servers (Slaves) from updating their records.Force the serial to use a dynamic timestamp (YYYYMMDDHH) in every automation script.
Open Zone Transfer (AXFR)MediumEavesdropping attacks revealing all subdomains on the network due to lack of ACLs.Define allow-transfer { none; }; or specify ACLs in /etc/named.conf.
Rotated LogsLowFailure to detect attacks or timeouts due to lack of dynamic monitoring.Configure active syslog and rotate named.log without deleting recent audit files.
TTL Cache DelayMediumExternal traffic still routed to the obsolete IP due to stale caches.Plan migration by lowering TTL values days before final script execution.

Production takeaways#

A full day: from Next.js build errors to network automation via Regex in the terminal. Identifying and resolving syntax and infrastructure bottlenecks ensures absolute control of the operational stack in a robust and scalable way.

Was this article helpful?

Leave a quick reaction to help prioritize future technical guides:

CC BY-NC

This post is licensed under CC BY-NC.

Comments

Join the discussion below.

0 comments