🚀 DirectAdmin Hosting & App Deployment
✍️ Short Summary
This end‑to‑end guide shows DirectAdmin customers and web/app developers how to deploy, secure, and maintain production websites and APIs on example.com. It covers DNS, SSL, SSH, Node.js/Passenger apps, PHP sites, databases (MySQL/MariaDB), logs, backups, and troubleshooting—optimized for speed, reliability, and clarity.
📎 Table of Contents
-
Getting Access (DirectAdmin, SSH, SFTP)
-
Pointing Your Domain (DNS → example.com)
-
Free HTTPS (Let’s Encrypt) & HSTS
-
App Layout on the Server
-
Deploying a Node.js + Express API with Passenger (behind Apache/Nginx)
-
PHP Website or Backend (FastCGI/PHP‑FPM)
-
Database Setup (MySQL/MariaDB) & Secure Access
-
Environment Variables & Secrets
-
Logs, Monitoring, and Alerts
-
Zero‑Downtime Updates & Rollbacks
-
Backups & Restores
-
Performance Tuning
-
Security Hardening
-
Common Errors & Fixes
-
Release Checklist (copy/paste)
-
Reference Commands (cheatsheet)
🔎 Who is this for? DirectAdmin end‑clients and their developers. Use it as your standard operating procedure (SOP) for hosting and app operations.
1) 🔐 Getting Access (DirectAdmin, SSH, SFTP)
DirectAdmin
-
URL:
https://example.com:2222
-
Create users: Admin → Account Manager → Create User
-
Enable 2FA: User → Security Questions / Two-Step Authentication
SSH (shell)
ssh username@example.com -p 22
Keys: Add your public key in User → SSH Keys. Disable password login if possible.
SFTP (files)
-
Host:
example.com
, Port:22
, Protocol: SFTP -
User: your DirectAdmin username
2) 🌐 Pointing Your Domain (DNS → example.com)
Set these at your domain registrar (or use the server’s DNS if provided).
A/AAAA records
A @ 203.0.113.10 ; example.com → server IPv4
A api 203.0.113.10 ; api.example.com
AAAA @ 2001:db8::10 ; if IPv6 available
CNAME (optional)
CNAME www example.com.
Propagation check:
dig +short A example.com
dig +short A api.example.com
3) 🔒 Free HTTPS (Let’s Encrypt) & HSTS
In DirectAdmin → Account Manager → SSL Certificates → Let’s Encrypt:
-
Select your domain(s):
example.com
,www.example.com
,api.example.com
. -
Check Force SSL and Redirect HTTP to HTTPS (in Domain Setup or HTACCESS).
-
(Optional) Enable HSTS:
# .htaccess (public_html/ or app root)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
4) 📁 App Layout on the Server
/home/USERNAME/
domains/
example.com/
public_html/ # public web root (static/PHP)
private/ # app code not publicly served
slkapi/ # example API app
server.js
routes/
db.js
package.json
tmp/ # Passenger restart file, boot logs, etc.
backups/
✅ Keep application code outside
public_html
unless it must be public.
5) 🟩 Deploying a Node.js + Express API with Passenger
Why Passenger? DirectAdmin often uses Apache/Nginx + Passenger to run Node.js apps efficiently.
5.1 Install app dependencies (per user)
cd ~/domains/example.com/private/slkapi
node -v && npm -v
npm ci --only=production || npm install --production
5.2 Minimal server.js
(health checks, JSON API, graceful errors)
// server.js
const express = require('express');
const fs = require('fs');
const path = require('path');
const PORT = process.env.PORT || 5000;
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// boot log
const TMP = path.join(__dirname, 'tmp');
try { fs.mkdirSync(TMP, { recursive: true }); } catch {}
const BOOT_LOG = path.join(TMP, 'boot.log');
const log = (...a) => { const s=a.map(x=>typeof x==='string'?x:JSON.stringify(x)).join(' ');
console.log(s); try{fs.appendFileSync(BOOT_LOG, s+'
');}catch{} };
// health
app.get('/', (req,res)=>res.json({status:'OK',message:'API root'}));
app.get('/api', (req,res)=>res.json({status:'OK',message:'API base under /api'}));
// routers
app.use('/api/boardMembers', require('./routes/boardMembers'));
app.use('/api/poojaDetails', require('./routes/poojaDetails'));
app.use('/api/festivalDetails', require('./routes/festivalDetails'));
// 404 + errors (json)
app.use('/api', (req,res)=>res.status(404).json({error:'Not found', path:req.originalUrl}));
app.use('/api', (err,req,res,next)=>{ log('ERR', err.stack||err.message); res.status(500).json({error:'Internal Server Error'}); });
app.listen(PORT, ()=>log('listening on', PORT));
5.3 Hook Passenger to your app
In public_html/ create a passenger-node
entry point (app.js
):
// public_html/app.js — Passenger entry
const path = require('path');
process.chdir(path.join(__dirname, '..', 'private', 'slkapi'));
require('./server');
Passenger auto‑detects Node apps in the web root. If you already have an app.js
there, only update the process.chdir
path.
5.4 Restart Passenger
cd ~/domains/example.com/private/slkapi
mkdir -p tmp && touch tmp/restart.txt
Verify:
curl -sS https://example.com/api/ | jq .
5.5 Debug mounted routes
Add a debug route:
app.get('/api/_routes', (req,res)=>{
const out=[]; const scan=(st,p='')=>st.forEach(l=>{ if(l?.route){
out.push({path:p+l.route.path,methods:Object.keys(l.route.methods)});
} else if(l?.name==='router' && l.handle?.stack){ scan(l.handle.stack, p+(l.regexp?.fast_slash?'':(l.path||''))); }});
if(app._router?.stack) scan(app._router.stack);
res.json({routes:out});
});
6) 🟦 PHP Website or Backend (FastCGI/PHP‑FPM)
-
Upload PHP to
public_html/
. -
Select PHP version: User → Select PHP Version.
-
Composer:
cd ~/domains/example.com/public_html
php -v
php -d detect_unicode=0 ~/composer.phar install --no-dev --optimize-autoloader
7) 🗃️ Database Setup (MySQL/MariaDB)
Create DB & user in DirectAdmin
Account Manager → MySQL Management → Create new Database
-
DB name:
example_db
-
User:
example_user
-
Strong password
Connect from Node.js (mysql2)
db.js
const cfg = (()=>{ try{ return require('./config'); }catch{return {}; } })();
const mysql = require('mysql2/promise');
module.exports = mysql.createPool({
host: process.env.DB_HOST || cfg.DB_HOST || '127.0.0.1',
user: process.env.DB_USER || cfg.DB_USER || 'example_user',
password: process.env.DB_PASS || cfg.DB_PASS || 'REDACTED',
database: process.env.DB_NAME || cfg.DB_NAME || 'example_db',
port: Number(process.env.DB_PORT || cfg.DB_PORT || 3306),
waitForConnections: true, connectionLimit: 10, queueLimit: 0,
enableKeepAlive: true, keepAliveInitialDelay: 10000, connectTimeout: 20000,
});
DB connectivity test route
// routes/boardMembers.js
router.get('/_dbping', async (req,res)=>{
try{ const [rows]=await db.query('SELECT 1 ok, DATABASE() db, NOW() now'); res.json({ok:true, info:rows[0]}); }
catch(e){ res.status(500).json({ok:false, code:e.code, errno:e.errno, fatal:!!e.fatal, message:e.message}); }
});
Fix common DB errors
-
ER_ACCESS_DENIED_ERROR
: wrong user/password or missing privileges → reset in MySQL Management. -
ECONNRESET
after idle: enable keepalive (above), use a pool, or reconnect on error.
8) 🔑 Environment Variables & Secrets
Option A: .env
file (private/)
DB_HOST=127.0.0.1
DB_USER=example_user
DB_PASS=super-secret
DB_NAME=example_db
NODE_ENV=production
Load with dotenv
in server.js
(optional).
Option B: DirectAdmin custom environment
-
If your template supports it: User → Custom HTTPD Config or vendor plugin to set env in Apache/nginx/Passenger context.
Never commit secrets to Git.
9) 📜 Logs, Monitoring, and Alerts
-
Web logs:
~/domains/example.com/logs/
-
Passenger/Node logs: your app’s
tmp/boot.log
+ DirectAdmin’s application logs -
Tail live:
tail -f ~/domains/example.com/private/slkapi/tmp/boot.log
-
Uptime probe: add an external monitor hitting
https://example.com/api/
every 1–5 minutes.
10) 🔁 Zero‑Downtime Updates & Rollbacks
-
git pull
or upload new build intoprivate/slkapi/
-
npm ci --only=production
-
Run database migrations (if any)
-
Smoke test (curl health,
_routes
) -
touch tmp/restart.txt
(Passenger restarts quickly) -
If bad release:
git reset --hard <last-good>
→touch tmp/restart.txt
11) 💾 Backups & Restores
Files
-
DirectAdmin Create/Restore Backups (automate daily + 7/30 day retention)
-
Or manual:
tar -czf ~/backups/site-$(date +%F).tgz ~/domains/example.com
Database
mysqldump -u example_user -p example_db > ~/backups/db-$(date +%F).sql
mysql -u example_user -p example_db < ~/backups/db-YYYY-MM-DD.sql
Store off‑server (object storage) for disaster recovery.
12) ⚡ Performance Tuning
-
Keep Node hot (Passenger manages worker lifecycle)
-
Gzip/Brotli via server; cache static assets:
# .htaccess in public_html
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 7 days"
ExpiresByType application/javascript "access plus 7 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/jpeg "access plus 30 days"
</IfModule>
-
Use a CDN for images/assets if global audience.
13) 🛡️ Security Hardening
-
Force HTTPS + HSTS
-
Firewall: allow 80/443/22 only; restrict MySQL to localhost
-
SSH keys only; disable root SSH if you manage the server
-
Secrets in env, not code
-
Principle of least privilege for DB users
-
ModSecurity/WAF (if provided) and fail2ban (provider‑side)
14) 🧰 Common Errors & Fixes
-
404 Not Found on /api/ → the app isn’t mounted; check
server.js
, confirmtmp/restart.txt
touched, view/api/_routes
. -
Passenger “Error starting web application” → open app’s
tmp/boot.log
; runnode server.js
locally to catch syntax/runtime errors. -
ER_ACCESS_DENIED_ERROR
→ fix DB creds/privileges in DirectAdmin; retest/api/boardMembers/_dbping
. -
ECONNRESET
→ use pooled connections and keepalive (seedb.js
). -
CORS issues → set explicit CORS headers in Express if calling from browsers.
15) ✅ Release Checklist
-
DNS records → correct IPs (A/AAAA)
-
Valid HTTPS (Let’s Encrypt) on all hostnames
-
App code in
private/
, public files inpublic_html/
-
npm ci --only=production
completed -
server.js
mounts routers at/api/...
-
DB credentials verified;
_dbping
passes -
Logs clean after
touch tmp/restart.txt
-
Smoke tests:
GET /api/
, critical endpoints return 200 -
Backups scheduled and tested restore
16) 🧾 Reference Commands (Cheatsheet)
# SSH
ssh username@example.com
# Passenger restart
cd ~/domains/example.com/private/slkapi && mkdir -p tmp && touch tmp/restart.txt
# Health checks
curl -sS https://example.com/api/ | jq .
curl -sS https://example.com/api/_routes | jq .
# Logs
tail -n 200 ~/domains/example.com/private/slkapi/tmp/boot.log
# DB ping (custom route)
curl -sS https://example.com/api/boardMembers/_dbping | jq .
🎯 Conclusion / Next Steps
You now have a complete, production‑ready workflow for hosting on DirectAdmin: DNS, SSL, app deployment with Passenger, DB connectivity, logging, backups, performance, and security. Use the checklist on every release. For teams, bake this guide into your onboarding and CI/CD runbooks for consistent, repeatable, and guaranteed results.