Separate cPanel account
Suitable for customers, isolated resource limits and separate FTP/email management. It may affect licensed account count.
This guide compares creating a separate cPanel account for every domain with using addon domains under one account and separate document roots. The ready Bash script includes domain validation, unique user generation, CSV results and retryable error logging.
whmapi1 createacct domain=ornek.com username=d123456789ab plan=domainpaket
/usr/local/cpanel/bin/cpapi2 --user=sitehesabi AddonDomain addaddondomain newdomain=ornek.com
/scripts/rebuildhttpdconf && /scripts/restartsrv_httpd
Bulk automation should not accelerate a wrong architecture. Decide customer isolation, resource limits, application roots, mail and DNS ownership first.
Suitable for customers, isolated resource limits and separate FTP/email management. It may affect licensed account count.
Creates less administrative overhead when all domains belong to you and separate directories are sufficient.
If every domain must show the same content, use redirects or aliases instead of duplicating sites.
Nameserver changes, A-record routing and Cloudflare bulk actions must be planned separately from panel domain creation.
Remove https://, www, paths, blank rows and duplicates. Convert IDN domains to Punycode.
sort -u domainler.txt | sed '/^[[:space:]]*$/d' > domainler-temiz.txt MOD=hesap creates a cPanel account per domain; MOD=addon creates separate folders under the target user.
MOD="addon" Validate the package, account limits, DNS role and API output with a small sample.
head -n 2 /root/domainler.txt > /root/domainler-test.txt Set file permissions to 700 and keep result files readable only by root.
chmod 700 /root/cpanel-toplu-domain.sh
/root/cpanel-toplu-domain.sh Extract failed domains into a separate list and rerun only those.
column -s, -t < /root/cpanel-domain-sonuclari.csv
cat /root/cpanel-domain-errorlari.log Verify DNS resolution first, then run AutoSSL in small batches.
dig +short ornek.com A
/usr/local/cpanel/bin/autossl_check --user=sitehesabi Runs in account or addon mode; writes results to CSV and errors to a separate log.
#!/usr/bin/env bash
set -Eeuo pipefail
MOD="addon"
DOMAIN_DOSYASI="/root/domainler.txt"
CPANEL_KULLANICI="sitehesabi"
PLAN="domainpaket"
ILETISIM="[email protected]"
SONUC="/root/cpanel-domain-sonuclari.csv"
HATA="/root/cpanel-domain-errorlari.log"
[[ "$EUID" -eq 0 ]] || { echo "root gerekli"; exit 1; }
[[ -f "$DOMAIN_DOSYASI" ]] || { echo "domain listesi bulunamadi"; exit 1; }
printf '"domain","mod","durum","kullanici","sifre"\n' > "$SONUC"
: > "$HATA"
chmod 600 "$SONUC" "$HATA"
while IFS= read -r SATIR || [[ -n "$SATIR" ]]; do
DOMAIN="$(printf '%s' "$SATIR" | tr -d '\r' | tr '[:upper:]' '[:lower:]' | sed -E 's#^[[:space:]]+##;s#[[:space:]]+$##;s#^https?://##;s#^www\.##;s#/.*$##')"
[[ -z "$DOMAIN" ]] && continue
[[ "$DOMAIN" == \#* ]] && continue
if [[ ! "$DOMAIN" =~ ^[a-z0-9][a-z0-9.-]*\.[a-z]{2,63}$ ]]; then
printf '"%s","%s","gecersiz","",""\n' "$DOMAIN" "$MOD" >> "$SONUC"
continue
fi
HASH="$(printf '%s' "$DOMAIN" | sha256sum | cut -c1-12)"
KULLANICI="d${HASH}"
ALTALAN="eka${HASH}"
SIFRE="Eka!$(openssl rand -hex 12)A9"
if [[ "$MOD" == "hesap" ]]; then
CIKTI="$(whmapi1 --output=json createacct domain="$DOMAIN" username="$KULLANICI" password="$SIFRE" plan="$PLAN" contactemail="$ILETISIM" 2>&1 || true)"
if grep -Eq '"result"[[:space:]]*:[[:space:]]*1' <<< "$CIKTI"; then
printf '"%s","hesap","basarili","%s","%s"\n' "$DOMAIN" "$KULLANICI" "$SIFRE" >> "$SONUC"
else
printf '%s | %s\n' "$DOMAIN" "$CIKTI" >> "$HATA"
printf '"%s","hesap","errorli","%s",""\n' "$DOMAIN" "$KULLANICI" >> "$SONUC"
fi
else
KLASOR="domains/${DOMAIN}/public_html"
CIKTI="$(/usr/local/cpanel/bin/cpapi2 --user="$CPANEL_KULLANICI" --output=jsonpretty AddonDomain addaddondomain dir="$KLASOR" newdomain="$DOMAIN" subdomain="$ALTALAN" 2>&1 || true)"
if grep -Eq '"result"[[:space:]]*:[[:space:]]*1' <<< "$CIKTI"; then
printf '"%s","addon","basarili","%s",""\n' "$DOMAIN" "$CPANEL_KULLANICI" >> "$SONUC"
else
printf '%s | %s\n' "$DOMAIN" "$CIKTI" >> "$HATA"
printf '"%s","addon","errorli","%s",""\n' "$DOMAIN" "$CPANEL_KULLANICI" >> "$SONUC"
fi
fi
done < "$DOMAIN_DOSYASI"
echo "Tamamlandi: $SONUC"
echo "Errorlar: $HATA"
Check API tools, version and account limits.
whmapi1 version
/usr/local/cpanel/bin/cpapi2 --help | head
whmapi1 acctcounts
Display the domain inventory of the target cPanel account with UAPI.
uapi --user=sitehesabi DomainInfo list_domains
When necessary, rebuild Apache configuration and restart it in a controlled way.
/scripts/rebuildhttpdconf
/scripts/restartsrv_httpd
This is the primary production family supported by cPanel. On CloudLinux, use the full cpapi2 path and check LVE/domain limits separately.
cat /etc/os-releasecloudlinux-summary get-licenses 2>/dev/null || truelveinfo --period=1h 2>/dev/null | headVerify operating-system support for your installed cPanel version; service names and package management can differ by distribution.
cat /etc/os-releasewhmapi1 versionsystemctl status cpanel --no-pagerWhen using a DNS cluster, test zone synchronization and cluster roles before the bulk operation.
whmapi1 listdnszones | head/scripts/dnscluster syncallwhmapi1 get_nameserver_configCan be caused by username collision, package name, account limits or an existing domain on the server.
The domain may exist under another account, as a DNS zone or in stale userdata.
The command may not be running as root, the API feature may be disabled or the account lacks permission.
Remote domain checks or DNS resolution may show that the domain points to another IP.
A/AAAA records, CAA, proxying or the HTTP validation path may be incorrect.
No matching error was found.
It can work when all domains have the same owner and application isolation is unnecessary. Separate accounts are better for different customers, resource limits or security boundaries.
cPanel marks API 2 as deprecated but explicitly states that no equivalent UAPI function exists for AddonDomain::addaddondomain. Test it on your installed version.
AutoSSL can be used after DNS points to the server. Do not start validation for hundreds of domains at once before checking propagation.
Use the Punycode form in panel and API operations; the Unicode display form can be stored separately.
Yes. Remove successful entries from the source list and rerun only failed domains. Adding an existing-domain check also makes the script idempotent.
No. Technical SEO, original content, valid structured data and internal links support visibility, but rankings cannot be guaranteed.
We implement panel selection, DNS, SSL, web server, security, backup and verification according to your actual server architecture.