Someone on r/programare had just started a small hosting company and asked for honest feedback. I looked at the site and found exactly the mistakes I see at almost everyone who starts out. No names, this isn't about him. It's about the pattern, because it keeps repeating.
I've been doing hosting for a while and I've made some of these mistakes myself. So this list comes from experience, not theory, and every point comes with the commands to check and fix it.
1. Don't put your DNS on the same server as your websites
The most common mistake: ns1 and ns2 point to the same IP, which is the very server hosting the sites.
Why it matters: when that server goes down, the sites aren't the only thing that goes. DNS goes too. Your customers lose their websites and their email, because mail servers trying to deliver to them can't find the MX record anymore, and after a while the mail starts bouncing. Two nameservers on one IP isn't redundancy, it's the same single point of failure written twice.
Check:
dig +short NS yourdomain.com
dig +short ns1.yourdomain.com A
dig +short ns2.yourdomain.com A
If the two IPs are identical, or even in the same /24 at the same provider, you have a problem.
What to do:
- At minimum: a second nameserver on a separate VPS at another provider, as a secondary that receives the zones by transfer (AXFR/IXFR).
- Simpler: use a managed DNS for your zones, for example Cloudflare, deSEC or Hurricane Electric (free), and keep the server for web and mail only.
- cPanel/WHM has a built-in DNS cluster: join a second DNS server to the cluster and the zones sync on their own.
A secondary with BIND on a separate VPS (/etc/bind/named.conf.local):
zone "yourdomain.com" {
type secondary;
primaries { PRIMARY_SERVER_IP; };
file "/var/cache/bind/yourdomain.com.db";
};
On the primary, allow transfers only to the secondary (allow-transfer { SECONDARY_IP; };) and send notify on every change.
2. Don't sell DDoS protection you don't have
"DDoS protection at datacenter level" looks good on a pricing page. In reality, at most big server providers that's the basic filtering every customer gets for free. It protects you from a simple volumetric flood, not from a targeted application attack (layer 7), like thousands of HTTP requests per second against a login page.
And customers check. Not all of them, but the ones that matter do. It takes ten seconds to find where a site really lives:
dig +short yourdomain.com A
whois IP | grep -iE "netname|descr|origin|country"
Or on bgp.tools and check-host.net, which also show the ASN and which countries the server answers from.
If your servers are at a dedicated server provider in Germany, say so clearly on the site. That's perfectly fine. What's not fine is implying you have your own anti-DDoS infrastructure when you have the datacenter's standard protection.
Long term, if you want to sell real protection:
- Get your own ASN (through RIPE, directly or via an LIR).
- Lease an IPv4 /24 (IPXO and other leasing platforms) or buy one.
- Take upstream from a provider that's serious about anti-DDoS, one that announces your prefix and filters before the traffic reaches you.
- For layer 7 you need a reverse proxy that can tell a human from a bot, not just a firewall.
A small help here: xTQ Web, my web server and reverse proxy. It's easier to configure than nginx or Caddy, has automatic HTTPS and flood protection out of the box, and can sit in front of an nginx (or Apache, LiteSpeed) you already run without any trouble. A whole site is one line:
bind 0.0.0.0:80
https 0.0.0.0:443
site example.com www.example.com { proxy 127.0.0.1:8080 }
Install it with curl -fsSL https://xtq.ro/web/install.sh | sh, and the full documentation is at xtq.ro/web/docs. It's free for personal and non-commercial use. A hosting company is commercial use, so you'll need a license, write to me and we'll work something out.
It also has agentic support: there's a guide written for AI agents, so you can tell Claude, ChatGPT or Gemini "install xTQ Web on my server and put my site behind it" and it knows exactly what to do, safely. The owner doesn't need to be technical.
Until then, you can do quite a lot on the server itself.
Kernel settings against SYN floods and half-open connections (/etc/sysctl.d/99-hosting.conf):
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_synack_retries = 2
net.core.somaxconn = 4096
net.ipv4.conf.all.rp_filter = 1
Apply with sysctl --system.
Rate limiting at the web server, for example in nginx:
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;
server {
location / {
limit_req zone=perip burst=40 nodelay;
limit_conn conn 30;
}
location = /wp-login.php {
limit_req zone=perip burst=5;
}
}
LiteSpeed/OpenLiteSpeed has the equivalent under "Per Client Throttling", and cPanel with CloudLinux already gives you per-account resource limits (LVE), so one customer can't take the whole server down.
Automatic bans for anyone guessing passwords or scanning (fail2ban, /etc/fail2ban/jail.local):
[sshd]
enabled = true
maxretry = 5
bantime = 1h
[nginx-limit-req]
enabled = true
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 1h
Or CrowdSec, which does the same but shares bad-IP lists between everyone running it.
3. Mail: IP reputation matters more than SPF
If you promise customers their mail won't land in spam, this is the part you have to do best. SPF, DKIM and DMARC are mandatory, but they're not enough: if the IP you send from has a poor reputation, mail lands in spam no matter how correctly it's signed. Many ranges at budget server providers have exactly this problem.
Check everything that matters:
# PTR (reverse DNS): must exist and match the name in your HELO
dig +short -x MAIL_SERVER_IP
# SPF, DKIM, DMARC
dig +short TXT yourdomain.com | grep spf
dig +short TXT default._domainkey.yourdomain.com
dig +short TXT _dmarc.yourdomain.com
# is the IP on a blocklist?
for bl in zen.spamhaus.org bl.spamcop.net b.barracudacentral.org; do
r=$(echo MAIL_SERVER_IP | awk -F. '{print $4"."$3"."$2"."$1}')
echo "$bl: $(dig +short $r.$bl)"
done
An empty result on the last command means you're not listed. Note: Spamhaus doesn't answer queries coming through the big public resolvers (Google, Cloudflare), so run the check on the server, with its own resolver.
A starting DMARC record that only reports and blocks nothing:
_dmarc.yourdomain.com. TXT "v=DMARC1; p=none; rua=mailto:[email protected]"
Once the reports look clean for a few weeks, move to p=quarantine, then p=reject.
If the IP has a poor reputation: send through a relay with a good reputation (a dedicated SMTP service) or ask your provider for clean IPs. And test for real, not just with dig: send a mail to mail-tester.com and look at the score.
4. VPS hosting: use Proxmox, don't reinvent the wheel
If you sell VPS, don't build them by hand with virsh and scripts held together with tape. Proxmox VE is free, open source, runs KVM, and gives you everything a host needs out of the box: templates, cloning in seconds, per-VM limits, a per-VM firewall, snapshots, backups, multi-node clustering and an API you can wire to your billing panel. We run it in production.
Install it on a dedicated server with the official ISO, or on top of a clean Debian, and use ZFS for the disks (mirror or RAIDZ): you get cheap snapshots, compression and data integrity checks for free.
A cloud-init template, once
The idea: you build one template VM from an official cloud image, and every new VPS is a clone of it, configured automatically on first boot (user, SSH key, IP).
cd /var/lib/vz/template/iso
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2
qm create 9000 --name debian13-tpl --memory 2048 --cores 2 \
--net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-single --agent enabled=1 \
--serial0 socket --vga serial0
qm disk import 9000 debian-13-genericcloud-amd64.qcow2 local-zfs
qm set 9000 --scsi0 local-zfs:vm-9000-disk-0,discard=on,iothread=1 \
--ide2 local-zfs:cloudinit --boot order=scsi0
qm template 9000
A new customer VPS in seconds
qm clone 9000 101 --name client-101 --full
qm set 101 --cores 2 --memory 4096 \
--ciuser root --sshkeys /root/client-101.pub \
--ipconfig0 ip=203.0.113.10/24,gw=203.0.113.1 \
--nameserver 1.1.1.1
qm resize 101 scsi0 40G
qm start 101
Limits, so one customer can't hurt the others
# bandwidth on the network card (MB/s, 12.5 is about 100 Mbit/s)
qm set 101 --net0 virtio,bridge=vmbr0,rate=12.5
# disk read/write limits
qm set 101 --scsi0 local-zfs:vm-101-disk-0,discard=on,iothread=1,mbps_rd=200,mbps_wr=150,iops_rd=4000,iops_wr=2000
# how much CPU it may use, so it can't hog the node
qm set 101 --cpulimit 2 --cpuunits 100
Per-VM firewall and anti-spoofing: mandatory
This is the part beginners skip and then wonder why they got abuse reports. Without filtering, a customer can configure an IP that isn't theirs inside their VPS, or send packets with a spoofed source address, and the complaints come in your name.
Enable the firewall at datacenter level (in the UI or in /etc/pve/firewall/cluster.fw), then for each VM (/etc/pve/firewall/101.fw):
[OPTIONS]
enable: 1
ipfilter: 1
macfilter: 1
policy_in: ACCEPT
[IPSET ipfilter-net0]
203.0.113.10
With ipfilter: 1, the VM can only send traffic from the IPs in its set. Also set firewall=1 on the VM's network card (--net0 virtio,bridge=vmbr0,firewall=1), or the rules won't apply.
Backups with Proxmox Backup Server
Proxmox Backup Server (also free) does incremental, deduplicated backups: after the first full one, the next ones only send changed blocks, so you can back up hundreds of VPS every day without filling your storage. Put it on another server, in another location.
# after adding PBS as a storage named "pbs"
vzdump 101 --storage pbs --mode snapshot
# or scheduled for every VM, under Datacenter > Backup
And restore a test VM from backup now and then, so you know it works.
Automation
Everything above can be done through the Proxmox API (pvesh or HTTP), so you can wire VPS creation to billing: the customer pays, the VPS creates itself. There are ready-made modules for WHMCS and other panels, or you write your own flow.
pvesh get /nodes/$(hostname)/qemu --output-format json
5. Fair prices, not prices that bet on ignorance
Plenty of people think a high price means quality. I know not everyone knows how to check with check-host or bgp.tools where a server really is. But don't exploit those people.
A VPS resold from a budget provider at twice the price, with a page full of "premium" and "enterprise", isn't a business, it's a trap. Customers find out sooner or later, and in hosting your reputation is everything you have. Same with domains: if a .com costs much more with you than the usual registrar price, people will compare.
Build your price from the real cost plus your margin plus your work, and say clearly what the customer gets for the difference: fast support in their language, free migration, tested backups. That sells itself.
6. Backups: doing them isn't the point, restoring them is
"Daily backups" on the pricing page and "depends on the plan" in the FAQ is the kind of contradiction a customer finds exactly on the day they need a backup. Pick one policy and write the same thing everywhere.
For web hosting servers (without Proxmox Backup Server), backups must be off the server, encrypted and tested. An example with restic, to separate storage:
export RESTIC_REPOSITORY="sftp:[email protected]:/backups/server1"
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic init # once
restic backup /home /etc /var/lib/mysql-dumps --exclude-caches
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check # verify integrity
For databases, don't copy the files while MySQL is running. Dump first:
mysqldump --all-databases --single-transaction --routines --events | gzip > /var/lib/mysql-dumps/all-$(date +%F).sql.gz
And once a month, restore something on a test server. A backup you've never restored is a hope, not a backup:
restic restore latest --target /tmp/restore-test --include /home/client1
On cPanel, JetBackup does this for you, but the rule stays: the destination is in another location, and the restore test happens.
7. Updates, firewall and SSH, on every server
The basics I'd do on any new server, before the first customer:
# automatic security updates (Debian/Ubuntu)
apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
SSH with keys only, no root with a password (/etc/ssh/sshd_config.d/hardening.conf):
PasswordAuthentication no
PermitRootLogin prohibit-password
MaxAuthTries 3
A firewall with nftables, everything closed except what you use:
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif lo accept
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
tcp dport { 22, 80, 443 } accept
tcp dport { 25, 465, 587, 993, 995 } accept # only if you run mail on the server
}
}
On cPanel use the firewall the panel manages, and on Proxmox nodes the Proxmox firewall, not two firewalls fighting each other.
8. Monitoring and a status page
Your customers shouldn't hear from their visitors that their site is down. You should know first.
- External monitoring (from a different network than the server): Uptime Kuma on a separate VPS is free and simple.
- Alerts on your phone, not just by email.
- A public status page. It feels like admitting you have problems, but in practice it builds trust: people see you know what's going on.
Uptime Kuma, on a separate server:
docker run -d --restart=unless-stopped -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
And monitor more than "the site answers": each nameserver separately, port 25 for mail, and SSL certificate expiry.
9. Your website is the first thing a customer checks
Small things that hurt trust more than you'd think:
- "24/7 support" next to "response in 1-2 business days". Pick what you can actually keep, and write that.
- Missing images or leftover template text on the page.
- No reviews, no named customers. Ask your first happy customers for a few lines.
- Company name, registration number, address and clear policies. Honestly, many small hosts do this better than the big ones. Keep it.
In short
- DNS separate from web, at another provider.
- Say exactly what protection you have and where your servers are.
- Mail: PTR, SPF, DKIM, DMARC and an IP with a good reputation.
- VPS on Proxmox, with templates, limits, anti-spoofing and Proxmox Backup Server.
- Honest prices. Customers will compare.
- Backups somewhere else, tested monthly.
- Automatic updates, SSH with keys, firewall closed by default.
- External monitoring and a status page.
- A website that says the same thing everywhere.
None of it is hard. Together, it's the difference between a host people recommend and one they leave after the first incident.
If you need layer 7 protection for your site or your customers, write to me at [email protected] and let's talk.

Comments