From 210e71e3d86501e0764e1b94883235999e313d2a Mon Sep 17 00:00:00 2001 From: openclawd Date: Mon, 16 Feb 2026 08:30:14 +0000 Subject: [PATCH] feat: SEO + Nginx optimization - Update sitemap.xml to include /v1/health endpoint - Add proper 404 handling (JSON for API paths, HTML for browser paths) - Create optimized nginx config with gzip, cache headers, specific locations - Add logrotate configuration for DocFast logs - Add security headers and static asset caching --- logrotate-docfast | 13 +++++++ nginx-docfast.conf | 90 ++++++++++++++++++++++++++++++++++++++++++++++ public/sitemap.xml | 1 + src/index.ts | 48 +++++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 logrotate-docfast create mode 100644 nginx-docfast.conf diff --git a/logrotate-docfast b/logrotate-docfast new file mode 100644 index 0000000..2714cca --- /dev/null +++ b/logrotate-docfast @@ -0,0 +1,13 @@ +/var/log/docfast*.log { + weekly + rotate 4 + compress + delaycompress + missingok + notifempty + create 644 root root + postrotate + # Send USR1 signal to dockerized apps to reopen log files + /bin/kill -USR1 $(cat /var/run/docker.pid 2>/dev/null) 2>/dev/null || true + endscript +} \ No newline at end of file diff --git a/nginx-docfast.conf b/nginx-docfast.conf new file mode 100644 index 0000000..846c1d0 --- /dev/null +++ b/nginx-docfast.conf @@ -0,0 +1,90 @@ +server { + server_name docfast.dev www.docfast.dev; + + client_max_body_size 10m; + + # Enable gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types + text/plain + text/html + text/css + application/json + application/javascript + text/xml + application/xml + application/xml+rss + text/javascript; + + # Specific locations for robots.txt and sitemap.xml with caching + location = /robots.txt { + proxy_pass http://127.0.0.1:3100; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Cache for 1 day + expires 1d; + add_header Cache-Control "public, max-age=86400"; + add_header X-Content-Type-Options nosniff; + } + + location = /sitemap.xml { + proxy_pass http://127.0.0.1:3100; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Cache for 1 day + expires 1d; + add_header Cache-Control "public, max-age=86400"; + add_header X-Content-Type-Options nosniff; + } + + # Static assets caching + location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://127.0.0.1:3100; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Cache static assets for 1 week + expires 7d; + add_header Cache-Control "public, max-age=604800, immutable"; + add_header X-Content-Type-Options nosniff; + } + + # All other requests + location / { + proxy_pass http://127.0.0.1:3100; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 60s; + + # Security headers + add_header X-Content-Type-Options nosniff; + } + + listen 443 ssl; # managed by Certbot + ssl_certificate /etc/letsencrypt/live/docfast.dev/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/docfast.dev/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot +} + +server { + if ($host = docfast.dev) { + return 301 https://$host$request_uri; + } # managed by Certbot + + listen 80; + server_name docfast.dev www.docfast.dev; + return 404; # managed by Certbot +} \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml index a891bea..b866d17 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -2,4 +2,5 @@ https://docfast.dev/weekly1.0 https://docfast.dev/docsweekly0.8 + https://docfast.dev/v1/healthdaily0.3 diff --git a/src/index.ts b/src/index.ts index adc8fc4..c4e2813 100644 --- a/src/index.ts +++ b/src/index.ts @@ -183,6 +183,54 @@ app.get("/api", (_req, res) => { }); }); +// 404 handler - must be after all routes +app.use((req, res) => { + // Check if it's an API request + const isApiRequest = req.path.startsWith('/v1/') || req.path.startsWith('/api') || req.path.startsWith('/health'); + + if (isApiRequest) { + // JSON 404 for API paths + res.status(404).json({ + error: "Not Found", + message: `The requested endpoint ${req.method} ${req.path} does not exist`, + statusCode: 404, + timestamp: new Date().toISOString() + }); + } else { + // HTML 404 for browser paths + res.status(404).send(` + + + + + 404 - Page Not Found | DocFast + + + + + +
+
+

404

+

Page Not Found

+

The page you're looking for doesn't exist or has been moved.

+

← Back to DocFast | Read the docs

+
+ +`); + } +}); + async function start() { // Initialize PostgreSQL await initDatabase();