Deployment
A concise guide to running BlockID in production. The marketing site is the application root, sign-in lives at /login.php, and the dashboard at /dashboard.php. For a fuller walkthrough, see the root /deployment.html.
Document root & routing
Point the web server's document root at the project root. The marketing homepage is served at / via DirectoryIndex. Clean public URLs include /product.php, /solutions.php, /pricing.php, /security.php, /compliance.php, /resources.php, /about.php, /contact.php, /request-demo.php, and /signup.php. Sign-in is /login.php, sign-out /logout.php, and the dashboard /dashboard.php. Dashboard internals live under /modules/**, the API under /api/v1/**, and these docs under /docs/**.
Apache
Set the document root and a directory index. Ensure mod_rewrite and .htaccess overrides are allowed if you use them.
<VirtualHost *:443>
ServerName your-domain
DocumentRoot /var/www/blockid
DirectoryIndex index.php
<Directory /var/www/blockid>
AllowOverride All
Require all granted
</Directory>
# Deny sensitive directories
<DirectoryMatch "^/var/www/blockid/(config|core|storage)">
Require all denied
</DirectoryMatch>
</VirtualHost>
Nginx
server {
listen 443 ssl;
server_name your-domain;
root /var/www/blockid;
index index.php;
location / { try_files $uri $uri/ /index.php?$query_string; }
# Deny sensitive directories
location ~ ^/(config|core|storage)/ { deny all; return 403; }
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Forward the Authorization header (for the API)
PHP behind some server configs won't see the Authorization header unless you forward it — which breaks Bearer-token auth with surprise 401s.
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
# or, with mod_rewrite:
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
Nginx (inside the PHP location)
fastcgi_param HTTP_AUTHORIZATION $http_authorization;
File permissions
- Application files: readable by the web user, not world-writable.
storage/(andstorage/logs/): writable by the web user so logs can be written.config/: writable only during install; tighten afterward soconfig/config.phpisn't world-readable.
Where config lives
Configuration is generated by the installer at config/config.php and holds your DB_HOST, DB_NAME, DB_USER, and related constants. Logs are written to storage/logs/php-error.log. Both directories are denied over HTTP.
HTTPS & security headers
Serve everything over TLS and add the recommended headers (HSTS, CSP, nosniff, frame protection, Referrer-Policy). See the Security → headers section for the full list, and the hardening checklist.
API endpoint setup
The API lives under /api/v1/** and needs nothing special beyond PHP and the forwarded Authorization header (above). Validate it with the health check:
curl https://your-domain/api/v1/health.php
See the API Guide for the full reference.
Backups
The ledger, credentials, DIDs, schemas, and audit logs all live in MySQL — so back up the database regularly and test restores. Keep backups encrypted and access-controlled.
mysqldump --single-transaction -u backup_user -p blockid > blockid-$(date +%F).sql
Final cleanup
/install after setup. Confirm /config, /core, and /storage return 403 over HTTP, and that display_errors is off in production.Security →
Headers, RBAC, ledger, and hardening.
Testing →
Verify routing, headers, and the API.
Troubleshooting →
Database, 403, CSRF, and API errors.