The admin dashboard (dashboard.html) and health endpoint (health.php) expose sensitive information about your API and MUST NOT be publicly accessible when running a production API.
If left unprotected, these files reveal:
- ✅ Total API requests processed
- ✅ Error rates and patterns
- ✅ Authentication failure attempts (shows attackers if their attacks are working!)
- ✅ Rate limiting hits (reveals abuse attempts)
- ✅ Average response times (performance data)
- ✅ System metrics (memory usage, CPU load, disk space)
- ✅ HTTP status code distribution
- ✅ Recent alerts and active issues
- ✅ Database connection status
- ✅ API health score
- ✅ System uptime
- ✅ Detailed statistics (same as dashboard, but JSON format)
- ✅ Prometheus metrics (for monitoring tools)
Attackers can use this information to:
- See if their attacks are working (auth failures, rate limits)
- Identify system weaknesses (high error rates, slow response times)
- Plan better attacks (know when system is under load)
- Map your infrastructure (system metrics reveal server capacity)
- Monitor their impact in real-time (dashboard auto-refreshes)
Example Attack Scenario:
Attacker visits: https://api.example.com/dashboard.html
Dashboard shows:
- Auth Failures: 450 (their brute force attack!)
- Rate Limit Hits: 890 (they know they need to slow down)
- Avg Response Time: 450ms (system is under load, good time to attack)
Attacker now knows:
✓ Their attack is working
✓ They're being rate limited (need to use more IPs)
✓ System is struggling (double down on attack)
Best for: Small teams, single office location, personal projects
Create or edit .htaccess in your project root:
# .htaccess
# Protect Admin Dashboard
<Files "dashboard.html">
Order Deny,Allow
Deny from all
# Allow from your office/home IP
Allow from 203.0.113.42
# Allow from IP range (e.g., office network)
Allow from 198.51.100.0/24
# Allow from localhost (development)
Allow from 127.0.0.1
Allow from ::1
</Files>
# Protect Health Endpoint
<Files "health.php">
Order Deny,Allow
Deny from all
# Allow from monitoring server
Allow from 203.0.113.42
# Allow from load balancer
Allow from 198.51.100.10
# Allow from localhost
Allow from 127.0.0.1
Allow from ::1
</Files>Add to your Nginx configuration:
server {
listen 80;
server_name api.example.com;
root /var/www/api;
# Public API endpoint - accessible to all
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Protect dashboard
location = /dashboard.html {
# Allow only specific IPs
allow 203.0.113.42; # Office IP
allow 198.51.100.0/24; # Office network
allow 127.0.0.1; # Localhost
deny all;
}
# Protect health endpoint
location = /health.php {
# Allow monitoring servers
allow 203.0.113.42; # Monitoring server
allow 198.51.100.10; # Load balancer
allow 127.0.0.1; # Localhost
deny all;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
include fastcgi_params;
}
}Testing:
# From allowed IP - should work
curl https://api.example.com/dashboard.html
# From other IP - should get 403 Forbidden
curl https://api.example.com/dashboard.html
# Response: 403 ForbiddenFind Your IP Address:
# Visit this URL in your browser:
https://whatismyipaddress.com/
# Or use command line:
curl https://api.ipify.orgBest for: Teams with remote workers, multiple locations, VPN users
# Create password file (run on your server)
htpasswd -c /etc/apache2/.htpasswd admin
# You'll be prompted to enter password
New password: ********
Re-type new password: ********
# Add more users (without -c flag)
htpasswd /etc/apache2/.htpasswd developer1
htpasswd /etc/apache2/.htpasswd manager# .htaccess
<Files "dashboard.html">
AuthType Basic
AuthName "Admin Dashboard - Authorized Personnel Only"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Files>
<Files "health.php">
AuthType Basic
AuthName "Health Monitoring"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Files>location = /dashboard.html {
auth_basic "Admin Dashboard";
auth_basic_user_file /etc/nginx/.htpasswd;
}
location = /health.php {
auth_basic "Health Monitoring";
auth_basic_user_file /etc/nginx/.htpasswd;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
include fastcgi_params;
}Accessing the Dashboard:
- Browser will prompt for username and password
- Enter credentials created with
htpasswd - Credentials are stored in browser session
For Monitoring Tools (Prometheus, etc.):
# prometheus.yml
scrape_configs:
- job_name: 'php-crud-api'
metrics_path: '/health.php?format=prometheus'
basic_auth:
username: 'monitoring'
password: 'secret-monitoring-password'
static_configs:
- targets: ['api.example.com']Best for: Production SaaS, enterprise applications, high-security requirements
/var/www/
├── api/ # Public API
│ ├── public/
│ │ └── index.php # Public endpoint (world accessible)
│ ├── config/
│ └── vendor/
│
└── admin/ # Admin panel (restricted)
├── dashboard.html # Protected dashboard
└── health.php # Protected health check
# Public API - Open to the world
<VirtualHost *:443>
ServerName api.example.com
DocumentRoot /var/www/api/public
SSLEngine on
SSLCertificateFile /etc/ssl/certs/api.crt
SSLCertificateKeyFile /etc/ssl/private/api.key
<Directory /var/www/api/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Block direct access to admin files if they exist here
<FilesMatch "^(dashboard\.html|health\.php)$">
Require all denied
</FilesMatch>
</VirtualHost>
# Admin Panel - Restricted access
<VirtualHost *:443>
ServerName admin-api.example.com
DocumentRoot /var/www/admin
SSLEngine on
SSLCertificateFile /etc/ssl/certs/admin-api.crt
SSLCertificateKeyFile /etc/ssl/private/admin-api.key
<Directory /var/www/admin>
Options -Indexes
AllowOverride All
# IP Whitelist
Require ip 203.0.113.42 # Office
Require ip 198.51.100.0/24 # VPN range
# AND Basic Auth (double protection)
AuthType Basic
AuthName "Admin Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Directory>
</VirtualHost># Public API
server {
listen 443 ssl http2;
server_name api.example.com;
root /var/www/api/public;
ssl_certificate /etc/ssl/certs/api.crt;
ssl_certificate_key /etc/ssl/private/api.key;
location / {
try_files $uri /index.php?$query_string;
}
# Block admin files
location ~ ^/(dashboard\.html|health\.php)$ {
deny all;
}
}
# Admin Panel
server {
listen 443 ssl http2;
server_name admin-api.example.com;
root /var/www/admin;
ssl_certificate /etc/ssl/certs/admin-api.crt;
ssl_certificate_key /etc/ssl/private/admin-api.key;
# IP Whitelist
allow 203.0.113.42; # Office
allow 198.51.100.0/24; # VPN
deny all;
# Additional Basic Auth
auth_basic "Admin Dashboard";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
try_files $uri $uri/ =404;
}
}DNS Configuration:
api.example.com A 203.0.113.100 (Public API server)
admin-api.example.com A 203.0.113.100 (Same server, different subdomain)
Access:
- Public API:
https://api.example.com/(world accessible) - Admin Dashboard:
https://admin-api.example.com/dashboard.html(restricted) - Health Check:
https://admin-api.example.com/health.php(restricted)
Best for: Maximum security, internal tools, enterprise environments
- Configure VPN (OpenVPN, WireGuard, etc.)
- Dashboard only accessible via VPN IP range
# .htaccess
<Files "dashboard.html">
Order Deny,Allow
Deny from all
# Only allow VPN IP range
Allow from 10.8.0.0/24
</Files>
<Files "health.php">
Order Deny,Allow
Deny from all
Allow from 10.8.0.0/24
</Files>Workflow:
- Team member connects to VPN
- Gets VPN IP (e.g., 10.8.0.50)
- Can now access
https://api.example.com/dashboard.html - Disconnect VPN → Access denied
Best for: Quick security, simple deployments
project-root/
├── public/ # Web-accessible (document root)
│ └── index.php # Public API only
├── admin/ # NOT web-accessible
│ ├── dashboard.html
│ └── health.php
├── config/
└── vendor/
<VirtualHost *:80>
ServerName api.example.com
# Document root points to public/ only
DocumentRoot /var/www/project-root/public
<Directory /var/www/project-root/public>
AllowOverride All
Require all granted
</Directory>
# Admin files are outside document root - not accessible via web
</VirtualHost>Access Admin Files:
- SSH into server
- Run:
php admin/health.php(command line) - Or create secure proxy script
For production SaaS APIs, use multiple layers:
# admin-api.example.com virtual host
<Directory /var/www/admin>
# Layer 1: IP Whitelist
Require ip 203.0.113.42
Require ip 198.51.100.0/24
# Layer 2: Basic Authentication
AuthType Basic
AuthName "Admin Dashboard"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
# Layer 3: SSL Certificate (client cert optional)
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /etc/ssl/certs/ca.crt
</Directory>To access, you need:
- ✅ Allowed IP address (office/VPN)
- ✅ Valid username/password
- ✅ Valid SSL client certificate (optional)
Attacker would need to compromise all three layers!
Solution: IP Whitelist (5 minutes)
<Files "dashboard.html">
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
Allow from YOUR_HOME_IP
</Files>Solution: Basic Auth (10 minutes)
- Create
.htpasswdwith team credentials - Everyone can access from anywhere
- Simple to manage
Solution: Separate Subdomain + IP Whitelist + Basic Auth (30 minutes)
- Maximum security
- Professional setup
- Easy to audit
Solution: VPN-Only + Client Certificates
- Maximum security
- Compliance-ready
- Full audit trail
After implementing security, test:
# From random IP/computer
curl https://api.example.com/dashboard.html
# Expected: 403 Forbidden or 401 Unauthorized
curl https://api.example.com/health.php
# Expected: 403 Forbidden or 401 Unauthorized# Public API should still work
curl https://api.example.com/?action=list&table=users
# Expected: API response (200 OK)# From allowed IP or with credentials
curl -u admin:password https://api.example.com/dashboard.html
# Expected: Dashboard HTML
curl -u admin:password https://api.example.com/health.php
# Expected: Health JSON# Prometheus should still be able to scrape
curl -u monitoring:secret https://api.example.com/health.php?format=prometheus
# Expected: Prometheus metricsAdd to Apache config:
<Files "dashboard.html">
# ... security config ...
# Log unauthorized attempts
CustomLog /var/log/apache2/admin-access.log combined
ErrorLog /var/log/apache2/admin-error.log
</Files># Check failed access attempts
tail -f /var/log/apache2/admin-error.log | grep "dashboard.html"
# Count attempts per IP
awk '{print $1}' /var/log/apache2/admin-error.log | sort | uniq -c | sort -nr# Create monitoring script
#!/bin/bash
# /usr/local/bin/monitor-admin-access.sh
THRESHOLD=10
COUNT=$(grep "dashboard.html" /var/log/apache2/admin-error.log | \
grep "$(date +%Y-%m-%d)" | wc -l)
if [ $COUNT -gt $THRESHOLD ]; then
echo "WARNING: $COUNT failed dashboard access attempts today!" | \
mail -s "Security Alert: Admin Dashboard" admin@example.com
fi# Nginx rate limiting
http {
limit_req_zone $binary_remote_addr zone=admin:10m rate=5r/m;
server {
location = /dashboard.html {
limit_req zone=admin burst=2 nodelay;
# ... other security config ...
}
}
}<Directory /var/www/admin>
Options -Indexes
</Directory><Directory /var/www/admin>
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "no-referrer"
</Directory>✅ DO:
- Protect dashboard and health endpoint from public access
- Use IP whitelisting for known locations
- Add HTTP Basic Auth for additional security
- Use separate subdomain for admin (production)
- Monitor failed access attempts
- Use HTTPS/SSL for all admin access
- Keep access logs for auditing
- Test security configuration regularly
❌ DON'T:
- Leave dashboard publicly accessible
- Use weak passwords for Basic Auth
- Share admin credentials publicly
- Expose health.php without authentication
- Ignore failed access attempts in logs
- Use HTTP (unencrypted) for admin access
If you've already deployed with public dashboard access:
- Block access immediately:
# Emergency .htaccess
<Files "dashboard.html">
Require all denied
</Files>
<Files "health.php">
Require all denied
</Files>- Check access logs:
grep "dashboard.html" /var/log/apache2/access.log
grep "health.php" /var/log/apache2/access.log- Look for suspicious IPs:
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -20- Change API keys if exposed
- Implement proper security (choose solution above)
- Monitor for next 24-48 hours
If you need help securing your installation:
- GitHub Issues: Report security concerns
- Email: security@example.com
- Documentation: Full security guide
Remember: Security is not optional for production APIs! 🛡️
The dashboard and health endpoint are powerful admin tools - treat them with the same security level as your database credentials.