В общем, случилось так, что 2 месяца назад на моём VDS сервере отказала ISPManager. Сколько бы я не пытался её переустановить — всё тщетно.

Так как мой хостер (FirstVDS) перестал предоставлять её бесплатно, то я решил вообще отказаться от панели и удалил её. Но, внезапно, сегодня мне понадобилось добавить поддомен на сервер и вот тут-то как раз без ISPManager'a пришлось тяжко.

Помучавшись пару часов, я наконец добавил домен вручную и написал небольшой shell-скрипт для автоматизации процесса.

UPD: Последняя версия скрипта находится в самом низу этой записи. Пожалуйста, используйте её.


Без поддержки PHP

#!/bin/bash
if [ "X$1" = "X" ]; then
echo "Usage: sh mkdomain.sh <domain name>"
exit 0
fi

if [ -f /etc/bind/$1 ]; then
echo "Domain $1 already exists"
exit 0
fi

SERVER_IP="IP_ВАШЕГО_СЕРВЕРА"
BASE_DOMAIN="ОСНОВНОЙ_ДОМЕН_СЕРВЕРА"
DOMAINS_FOLDER="ПАПКА_АПАЧА_С_ДОМЕНАМИ"
DOMAINS_OWNER="ВЛАДЕЛЕЦ_ДОМЕНА"
NS_ONE="NS_СЕРВЕР1"
NS_TWO="NS_СЕРВЕР2"
DATE="`date +%Y%m%d`01"

DOMAIN="\$TTL 3600
$1.    IN    SOA    $BASE_DOMAIN. root.example.com. ($DATE 10800 3600 604800 86400)
$1.    IN    NS    $NS_ONE.
$1.    IN    NS    $NS_TWO.
$1.    IN    TXT    \"v=spf1 ip4:$SERVER_IP a mx ~all\"
$1.    IN    MX    10 mx.yandex.ru.
$1.    IN    A    $SERVER_IP
www    IN    A    $SERVER_IP
ftp    IN    A    $SERVER_IP
mail    IN    A    $SERVER_IP
smtp    IN    A    $SERVER_IP
pop    IN    A    $SERVER_IP"

echo "$DOMAIN" >> /etc/bind/$1

ZONE="zone \"$1\" {
type master;
file \"/etc/bind/$1\";
};
"

echo "$ZONE" >> /etc/bind/named.conf

mkdir /var/www/$DOMAINS_OWNER/data/www/$1
echo "Nothing there" >> /var/www/$DOMAINS_OWNER/data/www/$1/index.html
VHOST="<VirtualHost $SERVER_IP:80>
ServerName $1
AddDefaultCharset utf-8
AssignUserID $DOMAINS_OWNER $DOMAINS_OWNER
DocumentRoot $DOMAINS_FOLDER/$1
ServerAdmin webmaster@$1
ServerAlias www.$1
CustomLog /var/www/httpd-logs/$1.access.log combined
ErrorLog /var/www/httpd-logs/$1.error.log
</VirtualHost>
<Directory $DOMAINS_FOLDER/$1>
Options +Includes -ExecCGI
</Directory>"
echo "$VHOST" >> /etc/apache2/vhosts/$DOMAINS_OWNER/$1
chmod 640 /etc/apache2/vhosts/$DOMAINS_OWNER/$1
chown $DOMAINS_OWNER $DOMAINS_FOLDER/$1
chown bind /etc/bind/$1
/etc/init.d/apache2 restart
/etc/init.d/bind9 restart

С поддержкой PHP
#!/bin/bash
if [ "X$1" = "X" ]; then
echo "Usage: sh mkdomain.sh <domain name>"
exit 0
fi

if [ -f /etc/bind/$1 ]; then
echo "Domain $1 already exists"
exit 0
fi

SERVER_IP="IP_ВАШЕГО_СЕРВЕРА"
BASE_DOMAIN="ОСНОВНОЙ_ДОМЕН_СЕРВЕРА"
DOMAINS_FOLDER="ПАПКА_АПАЧА_С_ДОМЕНАМИ"
DOMAINS_OWNER="ВЛАДЕЛЕЦ_ДОМЕНА"
NS_ONE="NS_СЕРВЕР1"
NS_TWO="NS_СЕРВЕР2"
DATE="`date +%Y%m%d`01"

DOMAIN="\$TTL 3600
$1.    IN    SOA    $BASE_DOMAIN. root.example.com. ($DATE 10800 3600 604800 86400)
$1.    IN    NS    $NS_ONE.
$1.    IN    NS    $NS_TWO.
$1.    IN    TXT    \"v=spf1 ip4:$SERVER_IP a mx ~all\"
$1.    IN    MX    10 mx.yandex.ru.
$1.    IN    A    $SERVER_IP
www    IN    A    $SERVER_IP
ftp    IN    A    $SERVER_IP
mail    IN    A    $SERVER_IP
smtp    IN    A    $SERVER_IP
pop    IN    A    $SERVER_IP"

echo "$DOMAIN" >> /etc/bind/$1

ZONE="zone \"$1\" {
type master;
file \"/etc/bind/$1\";
};
"

echo "$ZONE" >> /etc/bind/named.conf

mkdir /var/www/$DOMAINS_OWNER/data/www/$1
echo "Nothing there" >> /var/www/$DOMAINS_OWNER/data/www/$1/index.html
VHOST="<VirtualHost $SERVER_IP:80>
ServerName $1
AddDefaultCharset utf-8
AssignUserID $DOMAINS_OWNER $DOMAINS_OWNER
DocumentRoot $DOMAINS_FOLDER/$1
ServerAdmin webmaster@$1
ServerAlias www.$1
<FilesMatch '\.ph(p[3-5]?|tml)$'>
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch '\.phps$'>
SetHandler application/x-httpd-php-source
</FilesMatch>
php_admin_value sendmail_path '/usr/sbin/sendmail -t -i -f webmaster@$1'
php_admin_value upload_tmp_dir '$DOMAINS_FOLDER/../mod-tmp'
php_admin_value session.save_path '$DOMAINS_FOLDER/../mod-tmp'
php_admin_value open_basedir '$DOMAINS_FOLDER/..:.'
CustomLog /var/www/httpd-logs/$1.access.log combined
ErrorLog /var/www/httpd-logs/$1.error.log
</VirtualHost>
<Directory $DOMAINS_FOLDER/$1>
php_admin_flag engine on
Options +Includes -ExecCGI
</Directory>"
echo "$VHOST" >> /etc/apache2/vhosts/$DOMAINS_OWNER/$1
chmod 640 /etc/apache2/vhosts/$DOMAINS_OWNER/$1
chown $DOMAINS_OWNER $DOMAINS_FOLDER/$1
chown bind /etc/bind/$1
/etc/init.d/apache2 restart
/etc/init.d/bind9 restart

К сожалению, одного лишь скрипта тут недостаточно. Нужно еще добавить A-запись для нового поддомена на DNS-сервере. В случае с FirstVDS, если вы используете их NS адреса, необходимо зайти в DNSManager (FirstVDS) и добавить новый домен либо в виде master:

View post on imgur.com

Либо в виде A-записи для уже существующего домена:

View post on imgur.com

Всё тестировалось на VDS от FirstVDS с установленным Debian и виртуализацией KVM. На других конфигурациях думаю что-то будет отличаться, но суть та же.

P.S.: Пункта с DNSManager можно избежать если в скрипт добавить автоматическое добавление A-записи через API менеджера, но никакой внятной документации я для него еще не нашёл.


 

(26.09.14) UPD: Переписал скрипт. Теперь он более настраиваемый и прямо «из коробки» поддерживает nginx и PHP.

В новой версии всё разделено на несколько файлов. Сам скрипт, а также папка templates с шаблонами всех файлов, которые добавятся в систему в процессе его работы.

Напоминаю, что, пока что, всё также необходимо вручную добавлять запись в DNS Manager'e. Постараюсь исправить это в ближайшем будущем.

Скрипт
#!/bin/bash
if [ "$#" -ne 3 ]; then
echo "Usage: sh mkdomain.sh <domain name> <with PHP? (1/0)> <with nginx support? (1/0)>"
exit 0
fi
 
if [ -f /etc/bind/$1 ]; then
echo "Domain $1 already exists"
exit 0
fi

if [ ! -d templates ]; then
echo "Templates found not found"
exit 0
fi

# Directories
BIND_DOMAINS_DIR="/etc/bind"
APACHE_VHOSTS_DIR="/etc/apache2/vhosts/user"
NGINX_SITES_DIR="/etc/nginx/sites-enabled"
WWW_DIR="/var/www"

# Templates
APACHE_VHOST_TEMPLATE="vhost-template"
APACHE_VHOST_PHP_TEMPLATE="vhost-template-php"
NGINX_SITE_TEMPLATE="nginx-site-template"
INDEX_SITE_TEMPLATE="index.html"
BIND_DOMAIN_TEMPLATE="bind-domain-template"
BIND_ZONE_TEMPLATE="bind-zone-template"

# Server Settings
SERVER_IP="SERVER_IP_CHANGE_THIS_PLEASE"
BASE_DOMAIN="snouwer.ru"
DOMAINS_OWNER="user"
NS_ONE="ns1.firstvds.ru"
NS_TWO="ns2.firstvds.ru"
DATE="`date +%Y%m%d`01"
PORT="8080"
PORT_NGINX="80"

# Search and Replace in templates
if ! [ -d work ]; then
mkdir work
fi

cp templates/* work/
# I think there is more easier way to do this
sed -i "s:{{DOMAIN}}:$1:g" work/*
sed -i "s:{{WWW_DIR}}:$WWW_DIR:g" work/*
sed -i "s:{{BIND_DOMAINS_DIR}}:$BIND_DOMAINS_DIR:g" work/*
sed -i "s:{{SERVER_IP}}:$SERVER_IP:g" work/*
sed -i "s:{{BASE_DOMAIN}}:$BASE_DOMAIN:g" work/*
sed -i "s:{{DOMAINS_OWNER}}:$DOMAINS_OWNER:g" work/*
sed -i "s:{{NS_ONE}}:$NS_ONE:g" work/*
sed -i "s:{{NS_TWO}}:$NS_TWO:g" work/*
sed -i "s:{{DATE}}:$DATE:g" work/*
sed -i "s:{{PORT}}:$PORT:g" work/*
sed -i "s:{{PORT_NGINX}}:$PORT_NGINX:g" work/*

# Copying templates to right places

#bind
cat work/$BIND_ZONE_TEMPLATE >> $BIND_DOMAINS_DIR/named.conf
cp work/$BIND_DOMAIN_TEMPLATE $BIND_DOMAINS_DIR/$1

#apache
if [ $2 == "1" ]; then
    cp work/$APACHE_VHOST_PHP_TEMPLATE $APACHE_VHOSTS_DIR/$1
else
    cp work/$APACHE_VHOST_TEMPLATE $APACHE_VHOSTS_DIR/$1
fi

#nginx
if [ $3 == "1" ]; then
cp work/$NGINX_SITE_TEMPLATE $NGINX_SITES_DIR/$1
fi

#www
mkdir $WWW_DIR/$1
cp work/$INDEX_SITE_TEMPLATE $WWW_DIR/$1/

#finalizing
chmod 640 $APACHE_VHOSTS_DIR/$1
chown $DOMAINS_OWNER $WWW_DIR/$1
chown bind $BIND_DOMAINS_DIR/$1
rm -r work
#restarting services
/etc/init.d/apache2 restart
/etc/init.d/bind9 restart
if [ $3 == "1" ]; then
    /etc/init.d/nginx restart
fi