Server Overview
Key Hosted Sites / Services
| Domain / Service | User / Path | Type | Status |
|---|---|---|---|
| nexaforceai.in | nexaforceai | Docker | Live |
| api.nexaforceai.in | nexaforceai | Docker | Live |
| nexaforce-connector.marketmenia.com | /home/marketmenia/nexaforce-connector | Docker | Live |
| demo.marketmenia.com | /home/marketmenia/demo.marketmenia.com | PHP | Live |
| sandbox.marketmenia.com | /home/marketmenia/sandbox.marketmenia.com | PHP | Live |
| crm.safalacademy.com | hosted on this server | PHP | Live |
Users & Access
| User | Home | Role | Notes |
|---|---|---|---|
| root | /root | System administrator | Full access; session timeout configured in /etc/profile |
| nexaforceai | /home/nexaforceai | NexaForce Platform owner | Shell enabled via whmapi1 modifyacct … HASSHELL=1; added to wheel group with sudo; visudo configured |
| marketmenia | /home/marketmenia | MarketMenia account owner | Hosts connector, demo, and sandbox sites; also runs nexaforce-connector Docker stack |
| cashpeloan_dev | — | MySQL DB user | Access to cashpeloan_dev DB; needed Docker subnet grant (172.22.0.%) |
Switching Users
su - nexaforceai # switch to NexaForce user
sudo su - nexaforceai # from root with sudo
whmlogin # generate WHM one-time login URL (root only)Session Timeout
Root shell timeout was adjusted in /etc/profile (the TMOUT variable). Run source /etc/profile after editing for the change to take effect in the current session.
NexaForce Connector
A Docker-based middleware service that bridges the NexaForce AI Platform with the client's local MySQL database. Deployed under the marketmenia cPanel account.
Files
| File | Purpose |
|---|---|
| .env | All runtime config: DB credentials, webhook token, HMAC secret, NexaForce API URL |
| docker-compose.yml | Service definition; port mapped as 127.0.0.1:8090:8080 |
Key .env Variables
| Variable | Description |
|---|---|
| DB_HOST | MySQL host (Docker gateway IP, e.g. 172.22.0.1 or host.docker.internal) |
| DB_PORT | MySQL port (default 3306) |
| DB_USER | cashpeloan_dev |
| DB_PASSWORD | MySQL password for cashpeloan_dev |
| DB_NAME | cashpeloan_dev |
| DB_FIELD_MAP | JSON mapping of NexaForce field names → DB column names |
| NEXAFORCE_SECRET | HMAC-SHA256 signing secret (32-byte hex); must match NexaForce Platform config |
| WEBHOOK_TOKEN | Bearer token for inbound webhook from NexaForce (X-Webhook-Token header) |
| NEXAFORCE_API_URL | https://api.nexaforceai.in |
Common Operations
# Start / restart
cd /home/marketmenia/nexaforce-connector
docker compose up -d
# Pull latest image and restart
docker compose pull && docker compose up -d
# Check status
docker compose ps
# View live logs
docker compose logs connector -f
# Health check
curl http://localhost:8090/health
curl https://nexaforce-connector.marketmenia.com/healthTest Lookup Endpoint
PHONE="919990671176"
BODY="{\"phone\": \"$PHONE\"}"
SECRET="<NEXAFORCE_SECRET from .env>"
SIG=$(python3 -c "import hashlib,hmac; print(hmac.new(b'$SECRET', b'$BODY', hashlib.sha256).hexdigest())")
curl -X POST https://nexaforce-connector.marketmenia.com/lookup \
-H "Content-Type: application/json" \
-H "X-NexaForce-Signature: $SIG" \
-H "X-NexaForce-Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-d "$BODY"Test Webhook Endpoint
curl -X POST https://nexaforce-connector.marketmenia.com/webhook \
-H "Content-Type: application/json" \
-H "X-Webhook-Token: <WEBHOOK_TOKEN from .env>" \
-d '{"phone": "919990671176", "name": "Test Lead", "loan_type": "personal"}'Apache Reverse Proxy
SSL termination is handled by Apache (cPanel AutoSSL). The connector domain proxies to 127.0.0.1:8090. The config was attempted at /etc/apache2/conf.d/nexaforce-connector.conf but on this cPanel server the correct path is the cPanel include system. If Apache breaks after editing conf.d, rename or remove the file and use cPanel's reverse proxy UI instead.
MySQL / Database
Grant Docker Subnet Access
Run this whenever the Docker network subnet changes or a new DB user is needed for the connector:
mysql -u root -p
-- Create user for Docker subnet (if not exists)
CREATE USER IF NOT EXISTS 'cashpeloan_dev'@'172.22.0.%' IDENTIFIED BY '<password>';
-- Grant SELECT on the lead table (minimum needed for /lookup)
GRANT SELECT ON cashpeloan_dev.lead TO 'cashpeloan_dev'@'172.22.0.%';
FLUSH PRIVILEGES;
EXIT;Find Docker Gateway IP
# Get the gateway IP the connector container uses to reach the host MySQL
docker inspect nexaforce-connector | grep Gateway
# or
ip route | grep dockerTest DB Connection from Inside Container
docker exec nexaforce-connector python3 -c "
import asyncio, aiomysql, os
async def test():
conn = await aiomysql.connect(
host=os.environ.get('DB_HOST'),
port=int(os.environ.get('DB_PORT', 3306)),
user=os.environ.get('DB_USER'),
password=os.environ.get('DB_PASSWORD'),
db=os.environ.get('DB_NAME'),
)
print('Connected OK')
async with conn.cursor() as cur:
await cur.execute('SELECT mobile_number FROM lead LIMIT 3')
print('Rows:', await cur.fetchall())
conn.close()
asyncio.run(test())
"Root .my.cnf
Root MySQL credentials may be stored in /root/.my.cnf for passwordless CLI access.
cat /root/.my.cnfApache / httpd
MPM Worker Tuning
A traffic spike caused Apache to hit MaxRequestWorkers. The limit was raised by editing httpd.conf directly (emergency fix). The proper way is via cPanel's Apache Global Configuration or /var/cpanel/conf/apache/local.
# Check current MPM and limits
apachectl -V | grep MPM
apachectl -t -D DUMP_RUN_CFG | egrep "ServerLimit|MaxRequestWorkers|ThreadsPerChild"
# Check local cPanel overrides
grep -i "maxclients\|maxrequestworkers\|serverlimit" /var/cpanel/conf/apache/localEssential Commands
# Test config syntax
/usr/local/apache/bin/apachectl -t
# Graceful reload (preferred — no dropped connections)
/usr/local/cpanel/scripts/restartsrv_httpd
# or
systemctl reload httpd
# Full restart (use only if reload fails)
systemctl restart httpd
# Error log
tail -f /usr/local/apache/logs/error_log
tail -500 /usr/local/apache/logs/error_log
# Active connections on 80/443
ss -antp | grep ':80\|:443' | wc -lPHP-FPM
systemctl status php-fpm
journalctl -u php-fpm --since "1 hour ago"
grep -Ri "max_children\|slow\|timeout\|fatal" /opt/cpanel/ea-php*/root/usr/var/log/SSL Certificates
# Check AutoSSL for an account
/usr/local/cpanel/bin/autossl_check --user=marketmenia
# List installed certs
ls /var/cpanel/ssl/installed/certs/ | grep nexaforceDocker
Running Containers
| Container | Managed by | Notes |
|---|---|---|
| nexaforce-nextjs | nexaforceai user | Next.js frontend dashboard (has health check configured) |
| nexaforce-caddy | nexaforceai user | Reverse proxy / SSL for NexaForce containers |
| nexaforce_db | nexaforceai user | PostgreSQL for NexaForce platform (psql -U nexaforce nexaforce) |
| nexaforce-connector | marketmenia / root | CRM connector at /home/marketmenia/nexaforce-connector |
Useful Commands
# Overview
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker stats --no-stream
# Logs
docker logs --tail 300 nexaforce-nextjs
docker logs --since 30m nexaforce-nextjs
# Health check status
docker inspect nexaforce-nextjs | grep -A 50 Health
# Check NexaForce DB tables
docker exec nexaforce_db psql -U nexaforce nexaforce "\dt;"
# Check env inside container
docker exec nexaforce-connector env | grep DB_Firewall / CSF / Security
Block / Unblock an IP
# Block (permanent via CSF)
csf -d 35.240.162.123
# Block (immediate via iptables — not persistent across csf restart)
iptables -I INPUT -s 35.240.162.123 -j DROP
# Check current rules
iptables -L INPUT -n -v
csf -g 35.240.162.123 # grep CSF for an IPSMTP Redirect Issue (Jul 2026)
SMTP emails from PHP (port 587) were being silently redirected. The fix was removing a NAT redirect rule:
# Check if SMTP is being redirected
grep SMTP_REDIRECT /etc/csf/csf.conf
grep SMTP_BLOCK /etc/csf/csf.conf
iptables-save | grep REDIRECT
# If a rogue NAT rule exists, remove it
iptables -t nat -D OUTPUT -p tcp -m multiport --dports 25,465,587 -j REDIRECTCheck Outbound Connectivity
ping smtp.gmail.com
openssl s_client -connect smtp.gmail.com:587 -starttls smtpChange Timeline
Quick Reference
Daily Operations
# Health check all services
systemctl status httpd --no-pager
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
free -mh
uptime
# Check Apache error log (last 100 lines)
tail -100 /usr/local/apache/logs/error_log
# Connector health
curl https://nexaforce-connector.marketmenia.com/health
# Switch to NexaForce user to manage platform
sudo su - nexaforceaiGenerate a Secret Key
python3 -c "import secrets; print(secrets.token_hex(32))"cPanel Specific
# WHM one-time login URL
whmlogin
# Restart Apache via cPanel (preferred over systemctl)
/usr/local/cpanel/scripts/restartsrv_httpd
# Run AutoSSL for a user
/usr/local/cpanel/bin/autossl_check --user=marketmenia
# Check cPanel version
cat /usr/local/cpanel/versionEmergency: Apache Won't Start
# 1. Test config
/usr/local/apache/bin/apachectl -t
# 2. Check for syntax errors — look at what file failed
grep -i "error\|invalid\|cannot" /usr/local/apache/logs/error_log | tail -20
# 3. If a conf.d file is the problem, back it up and remove
mv /etc/apache2/conf.d/problem-file.conf /etc/apache2/conf.d/problem-file.conf.bak
# 4. Restart
/usr/local/cpanel/scripts/restartsrv_httpdEmergency: Connector Down
cd /home/marketmenia/nexaforce-connector
docker compose ps # check status
docker compose logs connector --tail 50 # check errors
nano .env # verify credentials
docker compose down && docker compose up -d # full restart