Win7 RDP multiuser

Не работает удаленный рабочий стол на несколько пользователей после обновлений ноября 2014?
Сносим обновления KB2984972, KB3003743. После этого терминал снова отлично работает.

Резервные копии в Windows по сети

Используемые средства

К сожалению, Windows по сравнению с *nix-системами имеет очень слабый функционал для подготовки и копирования бэкапов. В последнее время имеется тенденция к улучшению (PowerShell), однако, полезных утилит все равно недостаточно. Обычные Windows-утилиты copy/xcopy очень плохо работают на большом количестве файлов. В интернете можно найти «продвинутую» версию xcopy под названием robocopy, именно её мы и будем использовать.

Полные бэкапы

Будем размещать резервные копии на сервере srv-bak. Копировать будем в сетевую шару \\srv-bak\bak\srv01, где srv01 — директория с именем сервера на бэкапном. Таким образом в одной директории будут храниться бэкапы с разных серверов.
На сервере с резервными копиями для каждой из них будем создавать директорию с текущей датой в качестве имени. Для удобства поместим исходные пути, которые нужно забэкапить, в файлик D:\backup\dirs.txt. Переносим всё это дело «на клавиатуру» и получаем такой скрипт:

set backupdir=\\srv-bak\bak\srv01
IF NOT EXIST %backupdir% (
	mkdir %backupdir%
)

set d=%date:~0,2%
set m=%date:~3,2%
set y=%date:~6,4%
set ndate=%y%%m%%d%

set dirsfile=D:\backup\dirs.txt

set dstpath=%backupdir%\%ndate%
IF NOT EXIST %dstpath% (
	mkdir %dstpath%
)

for /f "eol=; tokens=1 delims=" %%i in (%dirsfile%) do (
	mkdir "%dstpath%%%~pi%%~ni"
	robocopy "%%~di%%~pi%%~ni" "%dstpath%%%~pi%%~ni" /E /ZB /NP
)

Чтобы всё работало автоматически, добавляем скрипт в планировщик. Таким (простым!) способом можно бэкапить достаточно большие объемы. Единственный, но существенный, наблюдаемый баг — если какой-то из копируемых файлов занят, скрипт отработает некорректно.

Инкрементные/дифференциальные бэкапы

Приведённая схема с использованием robocopy позволяет делать и инкрементные бэкапы. Утилита имеет ключ, позволяющий копировать только файлы с определённой датой последнего изменения. Поэтому, можно модифицировать скрипт, чтобы он делал инкрементный бэкап: например копировал файлы изменившиеся за последние сутки.

set backupdir=\\srv-bak\bak\srv01
IF NOT EXIST %backupdir% (
	mkdir %backupdir%
)

set d=%date:~0,2%
set m=%date:~3,2%
set y=%date:~6,4%
set ndate=%y%%m%%d%

if "%d%"=="01" (
	set dstpath=%backupdir%\%ndate%
) ELSE (
	set dstpath=%backupdir%\d%ndate%
)

IF NOT EXIST %dstpath% (
	mkdir %dstpath%
)

set /A prev=1%d%-100-1
if %prev% LSS 10 (
	set prev=0%prev%
)

set dirsfile=D:\backup\dirs.txt

if "%d%"=="01" (
	for /f "eol=; tokens=1 delims=" %%i in (%dirsfile%) do (
		:: xcopy "%%~di%%~pi%%~ni" "%dstpath%%%~pi%%~ni\" /C /E /H /Y
		mkdir "%dstpath%%%~pi%%~ni"
		robocopy "%%~di%%~pi%%~ni" "%dstpath%%%~pi%%~ni" /E /ZB /NP
	)
) ELSE (
	for /f "eol=; tokens=1 delims=" %%i in (%dirsfile%) do (
		:: xcopy "%%~di%%~pi%%~ni" "%dstpath%%%~pi%%~ni\" /D:%m%-%prev%-%y% /C /S /H /Y
		mkdir "%dstpath%%%~pi%%~ni"
		robocopy "%%~di%%~pi%%~ni" "%dstpath%%%~pi%%~ni" /MAXAGE:2 /S /ZB /NP
		rmdir "%dstpath%%%~pi%%~ni"
	)
)

IF EXIST %dstpath% (
	rmdir %dstpath%
)

Заключительные замечания

Вместо копирования по сети иногда бывает полезным разбиение этой задачи на 2 части: монтирование шары как локального диска и последующее копирование (и размонтирование по окончании). Приведённые скрипты несложным образом дорабатываются до такой версии.
Также, на принимающем сервере возможно организовать архивирование резервных копий. Если для сервера бэкапов используется Samba, то в шелле это элементарно делается периодическим выполнением в директории с бэкапами архивации вроде:

find -mindepth 2 -maxdepth 2 -type d -ctime +7 -execdir /usr/local/bin/tar_and_remove.sh "{}" \;

или

find -mindepth 2 -maxdepth 2 -type d -ctime +7 -execdir rar a -t -m5 -r -rr1 -df -inul "{}.rar" "{}" \; &> /dev/null

Кроме этого, с никсового сервера эти бэкапы очень удобно копировать с помощью ssh/scp/rsync.

Зеркалирование TCP порта с помощью iptables

В ряде задач системного администрирования требуется зеркалировать один tcp-порт на другой. Типичный пример: закрытый почтовый smtp порт 25 у некоторых провайдеров. В этом случае удобно смапить один порт на другой порт того же сервера, чтобы почту можно было отсылать по обоим портам. С помощью iptables это легко реализуется

$IPTABLES -A FORWARD -p tcp --dport 2025 -j ACCEPT
$IPTABLES -t nat -A PREROUTING -p tcp -d $WAN_IPADDR --dport 2025 -j REDIRECT --to-ports 25

Или альтернативный вариант указать интерфейс:

$IPTABLES -A FORWARD -p tcp --dport 2025 -j ACCEPT
$IPTABLES -t nat -A PREROUTING -p tcp -i $WAN_DEV --dport 2025 -j REDIRECT --to-ports 25

После этого подключаться можно по обоим портам.

Настройка виртуализации Windows под KVM libvirt linux

Система будет тестовая и стабильность на ней не нужна, поэтому настраивать это все будем в дистрибутиве Debian jessie, который на данный момент является веткой testing.
Оригинальные и краткие руководства к действию можно найти на дебиане: KVM и QEMU. Ниже несколько подогнанная под мои задачи выжимка.

Шаблон

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

virt-install --connect qemu:///system \
--name vm1 \
--ram 1024 \
--vcpus=1 \
--disk pool=storage,cache=none,size=40, format= qcow2\
--disk /vm/Win7.iso,device=cdrom \
--bridge=br0,model=e1000 \
--os-type=windows
--graphics vnc,port=5911,listen=0.0.0.0

но делать это постоянно очень неудобно. В качестве шаблона создаем конфиг вроде

<domain type='kvm'>
  <name>{name}</name>
  <memory>{ram}</memory>
  <currentMemory>{ram}</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type arch='x86_64' machine='pc-0.12'>hvm</type>
    <boot dev='cdrom'/>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='localtime'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/bin/kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='/vm/{name}.img'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='/vm/virtio.img'/>
      <target dev='hda' bus='ide'/>
      <address type='drive' controller='0' bus='0' unit='0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/vm/iso/ru_windows_8.1_professional_vl_with_update_x64_dvd_4050520.iso'/>
      <target dev='hdc' bus='ide'/>
      <readonly/>
      <address type='drive' controller='0' bus='1' unit='0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/vm/virtio-win-0.1-30.iso'/>
      <target dev='hdc' bus='ide'/>
      <readonly/>
      <address type='drive' controller='0' bus='1' unit='1'/>
    </disk>
    <controller type='ide' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <interface type='bridge'>
      <mac address='52:54:00:9d:be:d9'/>
      <source bridge='br0'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
    <input type='tablet' bus='usb'/>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='{port}' autoport='no' listen='0.0.0.0' keymap='en-us' passwd='{passwd}'/>
    <video>
      <model type='vga' vram='9216' heads='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </memballoon>
  </devices>
</domain>

Типовые шаблоны можно найти в документации, идущей вместе с пакетами. Также создаём устанавливающий скрипт vmcreate.sh:

#!/bin/sh

template=template.xml
path=/vm

while true; do
	read -p "VM name: " name
	if [ "$name" ]; then
		break
	fi
done


while true; do
	read -p "VNC port: " port
	case $port in
		[0-9]* ) break;;
	esac
done

while true; do
	read -p "VNC password: " password
	if [ "$password" ]; then
		break
	fi
done

while true; do
	read -p "HDD size in Gb [50]: " hdd
	case $hdd in
		[0-9]* ) break;;
		* )	hdd=50
			break;;
	esac
done

while true; do
	read -p "RAM in Mb [1536]: " ram
	case $ram in
		[0-9]* ) break;;
		* )	ram=1536
			break;;
	esac
done


echo "VM name: $name"
echo "VNC port: $port"
echo "Password: $password"
echo "HDD : $hdd Gb"
echo "RAM : $ram Mb"

while true; do
	read -p "Continue [y/N]? " yn
	case $yn in
		[Yy]* ) cont=1
			break;;
		* ) cont=0
			break;;
	esac
done

ramb=$((1024*$ram))

if [ -f "$path/$name.img" ]; then
#	cont=0
	echo "File $path/$name.img exist."
else
	qemu-img create -f raw "$path/$name.img" ${hdd}G
fi


if [ "$cont" -eq 1 ]; then
	sed "s/{name}/$name/g" $path/$template | sed "s/{port}/$port/g" | sed "s/{passwd}/$password/g" | sed "s/{hdd}/$hdd/g" | sed "s/{ram}/$ramb/g" > $path/$name.orig.xml
#	virsh create $name.orig.xml
	virsh define $name.orig.xml
	virsh start $name
else
	echo "Aborted."
fi

После такой подготовки виртуальная машина создается фактически запуском этого скрипта и ответом на вопросы. Конечную конфигурацию можно всегда поправить в XML-конфигах /etc/libvirt/qemu или с помощью утилиты virsh.

Типовая установка Windows в виртуалке

Драйвер от Win7 x64 вполне годится и для Windows 8.1, выбираем его при установке(Red Hat VirtIO SCSI controller, VIOSTOR.INF VirtIO Balloon Driver BALLOON.INF). Там же находим драйвер для сетевой карты, он пригодится позже. После этого виртуальный HDD находится системой, запускаем установку.
Уже на установленной системе ставим VirtIO-драйвер для Ethernet от Red Hat и настраиваем параметры сети.

Сеть

Для работы сети потребуется некоторая маршрутизация на самом хосте. Ниже представлен не самый оптимальный, но рабочий вариант для большинства (не-production) применений. А именно, разрешим forwarding на основной машине и явно пропишем пути из NAT-сети в интернет.
/etc/network/interfaces

up route add -host 10.0.5.2 dev br0

Также в местном фаерволле, т.е. скрипте, который настраивает iptables-правила, добавляем локальную сеть и нужные перенаправления:

IPTABLES=/sbin/iptables

echo 1 > /proc/sys/net/ipv4/ip_forward 2> /dev/null

ip addr add 10.0.6.1./24 dev br0
$IPTABLES -F -t nat
$IPTABLES -X -t nat

LAN="10.0.5.0/24"

$IPTABLES -A INPUT -s $LAN -j ACCEPT
$IPTABLES -A OUTPUT -s $LAN -j ACCEPT

$IPTABLES -t nat -A POSTROUTING -s $LAN -o br0 -j MASQUERADE

$IPTABLES -t nat -A PREROUTING -p tcp --dport 55003 -j DNAT --to-destination 10.0.5.3:3389

Управление с помощью утилиты virsh

Утилитой virsh совершаются штатно многие операции с вируалками. Наиболее часто используются старт, мягкая и жёсткая остановка

virsh start VMNAME
virsh shutdown VMNAME
virsh destroy VMNAME

Удалить существующую виртуальную машину (совсем!) также можно этой утилитой:

virsh undefine VMNAME

Как правило, виртуальная машина ставится надолго, поэтому её целесообразно стартовать при загрузке самой машины:

virsh autostart VMNAME

Завершающие дополнения

Конфиги виртуальных машин находятся в /etc/libvirt/qemu и могут быть исправлены до нужного состояния. В нём можно поменять физические параметры контейнера (объем ОЗУ, количество ядер и т.п.), также подключить/отключить образы жёстких дисков и CD/DVD.

На *nix-системах время обычно хранится в UTC, тогда как Windows его хранит в локальном часовом поясе. Проблему решает reg-файл следующего содержания:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation]
"RealTimeIsUniversal"=dword:00000001

htaccess-правила в apache2

Размещение правил в .htaccess лучше избегать, хотя бы по этой причине:

In the case of RewriteRule directives, in .htaccess context these regular expressions must be re-compiled with every request to the directory, whereas in main server configuration context they are compiled once and cached. Additionally, the rules themselves are more complicated, as one must work around the restrictions that come with per-directory context and mod_rewrite. Consult the Rewrite Guide for more detail on this subject.

Если коротко, то реврайты в .htaccess компилируются каждый раз при запросе к директории, тогда как в основном конфиге — только при запуске. На большом количестве запросов это может сделать апач быстрее.
Кроме того, размещение правил в основном конфиге безопаснее. В этом случае, поиск .htaccess отключается (что тоже имеет маленькое влияние на производительность — апач не ищет эти файлы).

Прописывайте правила в конфиге самого апача!

Собственные демоны в Linux с supervisor

Иногда возникает задача запускать некоторые процессы как демоны (daemons) и затем управлять их работой. Естественно, управление демоном лучше оформить со стандартным интерфейсом, т.е. похожим на известные

/etc/init.d/somedaemon {start|stop|restart|reload}

или более новомодно

service somedaemon {start|stop|restart|reload}

Чтобы не писать «велосипеды», можно воспользоваться supervisor. По сути он предоставляет инфраструктуру для управления демонами с логикой сходной с init.d-скриптами. Утилита отлично находится и ставится из репозитариев, конфиги к ней очень простые.

Разный вывод di и df в Linux

Интересные дела…

user@server:~$ di
Filesystem         Mount               Size     Used    Avail %Used  fs Type
/dev/md0           /                   1.9G     0.4G     1.4G   26%  ext4   
udev               /dev                5.9G     0.0G     5.9G    0%  tmpfs  
tmpfs              /dev/shm            5.9G     0.0G     5.9G    0%  tmpfs  
tmpfs              /lib/init/rw        5.9G     0.0G     5.9G    0%  tmpfs  
/dev/shm           /run/shm            5.9G     0.0G     5.9G    0%  none   
/dev/md1           /usr                9.4G     0.8G     8.1G   14%  ext4   
/dev/md3           /var                1.8T     0.1T     1.6T   11%  ext4   

user@server:~$ df 
Filesystem      1K-blocks      Used  Available Use% Mounted on
/dev/md0          1966404    416816    1449700  23% /
tmpfs             6163396         0    6163396   0% /lib/init/rw
udev              6157924       228    6157696   1% /dev
tmpfs             6163396         4    6163392   1% /dev/shm
/dev/md1          9842136    833200    8508972   9% /usr
/dev/md3       1899242804 108050616 1694716184   6% /var

phpmyadmin за SSL-фронтендом nginx

Администрировать БД MySQL часто бывает удобно с помощью phpmyadmin. Естественно, пользоваться им необходимо безопасно, т.е. через https.

Простой вариант решения заключается в указании явного URL для пхпмайадмина в его конфиге:

$cfg['PmaAbsoluteUri'] = 'https://admin.example.com/pma';

Это полностью рабочий и безопасный для других сайтов вариант, но требует правки конфига phpmyadmin.

Альтернативный вариант — передавать порт, по которому идет соединение на nginx front-end от пользователя. Для этого в стандартных настройках прокси для энжикса меняем

proxy_set_header Host $host;

на

proxy_set_header Host $host:$server_port;

Однако, последний способ выдает некоторые глюки на другом коде, который исполняется на том же домене.

Восстановление RAID 10 массива

Поломался однажды RAID10 массив. Как обычно, все произошло внезапно: однажды перезапустили сервер, и получили «(что-то там) … not found». С поврежденным (degraded) массивом сервер стартовать отказался. Массив работал на полусофтовом-полухардварном псевдоконтроллере материнской платы Intel. Физически все жесткие диски оказались здоровыми, хотя для нижеописанного это не критично.

Далее следует описание восстановления информации с массива из серии «с помощью швейцарского перочинного ножа», т.е. без применения изощрённых средств восстановления. Если конкретно, понадобится компьютер с любым *nix и интерпретатором python3. Можно, конечно, воспользоваться программами вроде R-Studio, однако, по-моему это слишком простая задача для них.

Итак, делаем следующее. Открываем в бинарном редакторе все 3 диска и выбираем из них пару striped дисков, т.е. на которых чередующимися блоками составляют весь массив (как RAID 0). Делаем образы обоих жестких дисков в файлы с помощью замечательной утилиты dd по типу

dd if=/dev/sdX of=/tmp/vY.hdd bs=32M

В итоге получаем два больших файла v0.hdd, v1.hdd. С самими HDD далее не работаем.

Снова открываем с помощью бинарного редактора какой-нибудь из образов и определяем размер stripe-элемента (chunk size). Сделать это не сложно даже «невооружённым взглядом»: ищется несколько этих кусков с чёткими границами. Легче всего это сделать на файле с вразумительным содержимом, или даже на любом — если свободное место (почти) заполнено нулями. В нашем случае размер stripe оказался 64K. При этом на одном из образов в начальном секторе сразу обнаружился MBR, а во втором нечто совсем не похожее на MBR. Так стал понятен порядок stripe от разных дисков.

Осталось почти ничего: брать поочередно chunks куски с разных дисков, складывать их последовательно и получить образ всего массива. Пишем для этого элементарный скрипт на питоне:

#!/usr/bin/python3
"""RAID0 recovery utility."""

dev0 = '/tmp/v1.hdd'
dev1 = '/tmp/v0.hdd'

DEV_OUT = '/tmp/out.hdd'

# stripe 64k
STRIPE = 64 * 1024
	
MAX_COUNT = 500 * 2**29 // STRIPE MAX COUNT

if __name__ == '__main__':
	f0 = open(dev0, 'rb')
	f1 = open(dev1, 'rb')

	f_out = open(DEV_OUT, 'wb')

	offset = 0
	while offset < MAX_COUNT:
		d0 = f0.read(STRIPE)
		d1 = f1.read(STRIPE)

		if d0 and d1:
			f_out.write(d0)
			f_out.write(d1)

			offset += 1
		else:
			print("One of input files are finished. Read: {0} blocks.".format(offset))
			break

	f0.close()
	f1.close()
	f_out.close()

Запускаем скрипт, оставляем его на ~10 минут и на выходе получаем полный образ диска. Разделы из него успешно монтируются самостоятельно или могут быть (всем образом) записаны на физический HDD. Так, совсем несложно и без дорогого софта, можно восстановить запоротый RAID10-массив.

LXC контейнеры в Debian jessie

LXC представляет собой набор утилит для управления виртуализацией на уровне операционной системы. Технология основана на механизме cgroups, которая позволяет создавать несколько Linux-окружений с собственным пространством процессов и сетевым стеком. Все контейнеры работают на одном ядре вместе с основной машиной, что делает виртуализацию этого типа очень эффективной. По этой причине виртуализация такого типа — отличный выбор для различных применений, где не требуется устанавливать дополнительные модули к ядру и подобная специфика.

Почти всю полезную информацию можно найти в дебиановском источнике. Ниже — наиболее короткий howto, как быстро настроить lxc-виртуализацию под Debian Linux.

Настройка хост-машины

Начинаем как обычно с установки необходимого софта

apt-get install lxc bridge-utils libvirt-bin debootstrap

Контейнеры будем создавать в стандартной директории /var/lib/lxc. Для удобства сделаем симлинк в корне файловой системы на эту директорию:

ln -s /var/lib/lxc

Настроим сеть. Для этого доустанавливается пакет bridge-utils, типовой конфиг сети (/etc/network/interfaces) будет следующим

auto lo
iface lo inet loopback

auto br0
iface br0 inet static
	address 123.123.123.3
	netmask 255.255.255.248
	gateway 123.123.123.1
	bridge_ports eth0
	bridge_fd 0
	bridge_maxwait 0
	bridge_stp off
	dns-nameservers 8.8.8.8 8.8.4.4

Проверяем, всё ли в порядке с установкой

lxc-checkconfig

и если все нормально, то ставим туда первый контейнер

lxc-create -n myvm -t debian

В результате получаем виртуальную машину и root-пароль к ней. Контейнер будет из stable-дистрибутива (Wheezy), однако его можно дообновить до testing или изначально ставить testing.

Настройка виртуальной машины

Конфиг виртуальной машины находится в /lxc/myvm/config. Доводим его до вменяемого состояния, например такого

lxc.network.type = veth
lxc.rootfs = /var/lib/lxc/myvm/rootfs

# Common configuration
lxc.include = /usr/share/lxc/config/debian.common.conf

# Container specific configuration
lxc.mount = /var/lib/lxc/myvm/fstab
lxc.utsname = myvm
lxc.arch = amd64


lxc.network.flags = up
lxc.network.link = br0

lxc.network.hwaddr = 00:25:90:01:5e:22

lxc.start.auto = 1

Последний параметр отвечает за автозагрузку при запуске основной машины.

Перед запуском виртуалки также меняем сетевые настройки в /etc/network/interfaces.

В новой системе только минимальный набор софта, который не включает в себя некоторые широкоизвестные и часто применяемые утилиты. Например, не получится сразу выполнить ping, поскольку соответствующего ему пакета нет в системе. Доустанавливаем необходимый софт:

apt-get install apt-utils iputils-ping cron rsyslog iptables

Иногда будем получать ругань вроде

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LANGUAGE = (unset),
        LC_ALL = (unset),
        LC_CTYPE = "ru_RU.UTF-8",
        LC_COLLATE = "ru_RU.UTF-8",
        LC_MESSAGES = "C",
        LC_NUMERIC = "POSIX",
        LANG = (unset)
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

Поэтому сразу конфигурируем локаль

dpkg-reconfigure locales

Стандартного почтового агента (MTA) в системе тоже нет, поэтому ставим его и настраиваем:

apt-get install exim4
dpkg-reconfigure exim4-config

Полезные команды для управления

Запустить и погасить виртуальную машину используются

lxc-start -n myvm -d
lxc-stop -n myvm

Параметр -d в случае старта означает запуск в режиме демона. Если его не указать, то getty захватит текущую консоль (что бывает полезно, если не удаётся подключиться по SSH).

Получить краткую информацию о статусе машины можно с помощью

lxc-info -n myvm

Заключение

Вышеприведенная конфигурация — очень быстрый способ поставить виртуальную машину, например для целей тестирования ПО. Если требуется даже базовая безопасность, необходимо много чего доработать.

PS

Статья устарела. Более качественный способ приведён в дебиановском мануале. И, что важно, постоянно обновляется.

Минимум в настройке почтовых серверов и рассылок

Часто бывает настроят сервер или полухостинг так, что веб работает, а почта отсылается не всегда. Такое же нередко можно наблюдать даже на достаточно крупных корпоративных почтовых серверах. Для минимально технически корректного использования нужно не так много сделать. А именно:

  • Убедитесь, что ваш почтовый сервер не open relay, т.е. не рассылает сообщения от неавторизованных пользователей. Проверьте сконфигурированный почтовый сервер на open relay в нескольких легко находимых в поисковиках сервисах.
  • В соответствии с RFC настройте обратный DNS (rDNS) для IP-адреса сервера и убедитесь, что возвращаемое доменное корректно разрешается и его A-запись — IP-адрес сервера. Иными словами доменное имя должно разрешаться в IP-адрес сервера, а IP-адрес — обратно разрешаться в то же доменное имя (FQDN). Именно это доменное имя должно возвращаться сервером в HELO/EHLO.
  • Настройте цифровую подпись DKIM. Её использование защитит вас от несанкционированной рассылки почты от вашего домена с серверов третьих лиц. По этой причине популярные почтовые сервисы используют её наличие при вычислении «спамовости» письма. После настройки DKIM, подпись следует проверить: в заголовках отосланных писем на серверах, проверяющих подпись, должна присутствовать запись dkim=pass.
  • Используйте антиспам и антивирусное ПО. В том числе и на исходящую почту. Если используете postfix, то на его сайте опубликован список поддерживаемого софта.
  • Настройте SPF. Целесообразность использования этой технологии иногда ставится под вопрос, поскольку она имеет недостаток: форвард с непрописанных серверов приведет к fail-результату по SPF. DKIM в этом смысле существенно более совершенная технология и в целом делает ненужным SPF. Тем не менее, в существующих реалиях её лучше использовать. Проверка, как и в случае с DKIM проста: в исходнике принятых с сервера писем должен быть результат spf=pass. SPF также имеет смысл включать на «непочтовых» доменах в виде "v=spf1 -all" для предотвращения отправки спама от этого домена.
  • Проверьте, что IP-адрес сервера не находится в черных списках, например этим тестом.

В случае почтовых рассылок обязательно необходимо проверить валидность заголовков письма. Например, если сообщение формируется как MIME multipart, убедитесь в правильном использовании Content-type для различных частей письма.

Debian hostname

Правильно настроенный хост должен возвращать следующие имена hostname:

  • короткое имя по hostname
  • FQDN по hostname -f
  • доменное имя по hostname -d

Ключи естественным образом взяты из мануала и результат этих команд — простой тест на правильную конфигурацию хостнейма. От корректности настройки зависит работа многих приложений на сервере, веба, почты и т.п.

Иногда на принимаемых серверах hostname настроен некорректно. Правится ситуация несложным образом:

  • Проверяем, что в /etc/hostname прописано короткое имя. Если нет, то прописываем.
  • Проверяем, что в /etc/hosts первым доменом на ip-адрес сервера прописан FQDN и если нет, то прописываем.
    1.2.3.4 somehost.prod.example.com somehost somehost.prod
    

После изменений перегружаем сервер для проверки, что весь софт правильно работает с загрузки сервера.

Дополнение:
Неправильный hosts, а точнее не-FQDN на первом месте после ip-адреса сервера приводит к ошибке apache2:

AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using XXX.XXX.XXX.XXX. Set the 'ServerName' directive globally to suppress this message                                                                                                 

Установка sphinx-плагина для memcached в Debian

Многие плагины к сфинксу в дебиане можно найти и подключить с помощью

munin-node-configure --suggest
munin-node-configure --shell

Однако, есть много стоковых плагинов в /urs/share/munin/plugins/, которые не предлагаются и не включаются таким способом. В частности, плагин к memcached подключается вручную. Ставится он коротко следующим образом.

Плагин требует перловскую библиотеку Cache::Memcached, если её нет в системе — ставим:

apt-get install libcache-memcached-perl

Далее вручную идем в директорию с конфигами и подключаем плагин:

cd /etc/munin/plugins
ln -s /usr/share/munin/plugins/memcached_ memcached_rates
ln -s /usr/share/munin/plugins/memcached_ memcached_bytes
ln -s /usr/share/munin/plugins/memcached_ memcached_counters

Что означают все показатели и как работает плагин можно посмотреть в самом perl-скрипте /usr/share/munin/plugins/memcached_.

Далее запускаем получившиеся симлинки и проверяем, что плагин работает. По окончании рестартуем munin-node:

Ограниченный SFTP-доступ на сервер

Часто возникает задача дать доступ на сервер в определенную директорию по протоколу sftp, чтобы при этом не было доступа в весь корень файловой системы. Т.е. используя технику chroot. Делается это следующим образом.

Сначала создается пользователь в системе. Обычно по sftp заходят для правки контента и группа пользователя назначается общей для этого рода пользователей (например, www-data). Всё это делается опциями к adduser или useradd.

Далее в /etc/ssh/sshd_config созданному пользователю newuser добавляется кусок конфига, который определяет параметры входа и chroot:

Match User newuser
	ChrootDirectory %h
	ForceCommand internal-sftp
	AllowTcpForwarding no
	X11Forwarding no

После изменения конфига, естественно, нужно рестартануть sshd.

На этом все не заканчивается. Вот что гласит мануал sshd_config:

ChrootDirectory
Specifies the pathname of a directory to chroot(2) to after authentication. All components of the pathname must be root-owned directories that are not writable by any other user or group. After the chroot, sshd(8) changes the working directory to the user’s home directory.

Из соображений безопасности, чтобы работал chroot, директория пользователя должна быть от пользователя root (при этом группа может быть не рутовой). Выполняем это требование, voila и всё работает.

Также для безопасности обычно имеет смысл отключить шелл пользователя

	usermod newuser -s /bin/false

PS: Это все применимо именно для sftp. К сожалению, для scp это не работает и при попытке подключиться по ssh/scp произойдет ошибка.

Полезные команды для работы с LSI raid массивами

Несколько ранее я уже писал о замене HDD в рейд-массивах контроллеров LSI с помощью оригинальной утилиты MegaCLI. Список полезных команд этой утилиты намного шире, здесь я сохраню наиболее полезные из них.

В командах используются следующие параметры:

  • Адаптер: -aN. На сервере может быть установлено несколько физических RAID-контроллеров, номер нужного указывается параметром -a. Обычно установлен только один контроллер, для этого случая будет стандартный параметр -a0. Значением ALL можно указать сразу все доступные контроллеры.
  • Логический (виртуальный) диск: -Lx. Вместо x идет номер диска (начиная с 0). Также, допустимо значение ALL, выбирающий все доступные диски контроллера.
  • Физический диск: -PhysDrv [E:S]. E (Enclosure) — это номер корзины, S (slot) — номер слота начиная с 0.

Информация о контроллерах, логических и виртуальных дисках

Информация о корзинах (Enclousure) на всех контроллерах:

./MegaCli64 -EncInfo -aALL

Просмотр всех настроек контроллера 0:

./MegaCli64 -AdpAllInfo -a0
./MegaCli64 -ShowSummary -a0
./MegaCli64 -CfgDsply -a0

Получить состояние всех логических дисков:

./MegaCli64 -LDInfo -LALL -aALL

Информация о логических (виртуальных) дисках, т.е. собственно RAID-массивах:

./MegaCli64 -LDInfo -L0 -aALL

Информация о состоянии конкретного физического диска

./MegaCli64 -pdInfo -PhysDrv [4:11] aALL

Статус ребилда

./MegaCli64 -PDRbld -ShowProg -PhysDrv [4:11] -aALL

Логи контроллера

Одна из наиболее полезных комманд, когда ничего вроде не случилось, но что-то работает не так — просмотр логов. Это делается с помощью:

./MegaCli64 -AdpEventLog -GetSinceReboot -f events.log -aALL
./MegaCli64 -AdpEventLog -GetLatest 10 -f t1.log -aALL

Проверка прошивки

./MegaCli64 -PDList -aALL | grep Firmware

Диски горячей замены [hotspare]

Назначение диском горячей замены для определенного массива:

./MegaCli64 -PDHSP -Set -Dedicated -Array0 -PhysDrv[4:2] -a0

Назначить глобальным HotSpare-диском:

./MegaCli64 -PDHSP -Set -PhysDrv[252:2] -a0

Снятие статуса диска горячей замены:

./MegaCli64 -PDHSP  -Rmv -PhysDrv[4:2] -a0

Назначение загрузочного массива

./MegaCli64 -AdpBootDrive -set -L0 -a0

Параметры HDD S.M.A.R.T.

Параметры SMART можно получить с помощью стандартной линуксовой утилиты smartctl, если явно указать контроллер и id диска. Заранее необходимо собрать id исследуемых дисков, это параметр 'Device Id' в списке физических дисков. Можно собрать и все доступные id:

./MegaCli64 -PDList -a0 | grep 'Device Id'

Теперь для искомых дисков можно запрашивать смарт-параметры, например для id=5:

smartctl -d sat+megaraid,5 -a /dev/sdb

locale failed in Debian

При установке в свежей ОС Debian новых пакетов обычно возникает ошибка вроде

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = «en_US:en»,
LC_ALL = (unset),
LC_CTYPE = «ru_RU.UTF-8»,
LANG = «en_US.UTF-8»
are supported and installed on your system.
perl: warning: Falling back to the standard locale («C»).

Для исправления нужно подключить локали, хватает русской и английской utf-8. Для этого:

dpkg-reconfigure locales

И там выбираем соответствующие en_US.UTF-8 и ru_RU.UTF-8.

Расширение LSI raid массива

Как и в случае замены проверяем диски:

./MegaCli64 -pdInfo -PhysDrv \[4:4\] -a0
./MegaCli64 -pdInfo -PhysDrv \[4:15\] -a0

Добавляем диски в массив:

./MegaCli64 -LDRecon -Start -r6 -Add -PhysDrv[4:4,4:15] -l2 -a0

После можно смотрим статус массива и процент завершения:

./MegaCli64 -LDInfo -LAll -aAll

Как убрать фигурные кавычки WordPress

Русский WordPress в стоковой конфигурации имеет плохую привычку заменять обычные кавычки на фигурные (французские). Особенно это досаждает, когда выкладывается какой-то код и в нем происходит автозамена.

К счастью, это легко исправляется. Для этого в файле /wp-includes/formatting.php находим строки, отвечающие за замену кавычек:

/* translators: opening curly double quote */
$opening_quote = _x( '&#8220;', 'opening curly double quote' );
/* translators: closing curly double quote */
$closing_quote = _x( '&#8221;', 'closing curly double quote' );

и в них меняем символы ‘&#8220;’, ‘&#8221;’ на ‘&quot;’.

PS: Да, с обновлением WP, код может снова поменяться на оригинальный. По-хорошему, такое надо делать с помощью утилит diff и patch.

Полезные твики bash

В этой статье наиболее полезные способы быстрой и продуктивной работы с коммандной строкой bash. Предполагается, что читатель уже несколько знаком с коммандной строкой, поэтому совсем тривиальных вещей, вроде использования Tab для автодополнения, здесь нет. В комментарии приветствуются другие полезные «твики» bash.

Алиасы

Листинги

alias ll='ls -l'
alias l='ls -lA'

Часто эти опции уже включены в .bashrc, но закомментированы. В Debian, например, в конфиге это реализовано так

# export LS_OPTIONS='--color=auto'
# eval "`dircolors`"
# alias ls='ls $LS_OPTIONS'
# alias ll='ls $LS_OPTIONS -l'
# alias l='ls $LS_OPTIONS -lA'

Остается раскомментировать нужные строчки. При этом в нагрузку получаем цветовую подсветку директорий.

Часто используемая команда по поиску процесса с определенным именем:

alias pg='ps aux | grep '

Просмотр наибольших файлов/директорий в гигабайтах и мегабайтах соответственно:

alias dug='du -h | grep ^[0-9.]*G | sort -rn'
alias dum='du -h | grep ^[0-9.]*M | sort -rn'

Полезности для скриптов

Иногда бывает полезным поймать сигналы, посылаемые ОС скрипту. Например, при нажатии Ctrl-C.

trap control_c SIGINT
trap control_c SIGTERM

Часто используемые команды

Часто бывает необходимо найти файл, в котором имеется определённая подстрока. Сделать это можно с помощью стандарной утилиты grep командой:

grep -rl

Горячие клавиши bash

  • Ctrl+w — удаляет слово перед курсором в строке,
  • Ctrl+u — удаляет все символы до начала строки,
  • Ctrl+k — удаляет все символы до конца строки,
  • Ctrl+y — вставляет удалённые вышеуказанными сочетаниями символы,
  • Ctrl+r — производит обратный поиск по истории команд,
  • Ctrl+l — очищает экран,
  • Ctrl+z — останавливает исполнение текущей команды (продолжить можно с помощью bg или fg),
  • Ctrl+d — выход из сессии.

История команд bash

В администрировании Linux (да и UNIX тоже) очень удобно пользоваться командами из истории. Содержание истории просматривается с помощью вызова history. Команду из истории можно выполнить по её номеру в списке например так:

history | less
!45

При этом последняя команда вызывается более просто, без указания номера выполнением !!.

Обратный поиск по истории команд вызывается с помощью Ctrl+R, например:

(reverse-i-search)`smart': smartctl -x /dev/sdd | less

Взять аргументы из одной из предыдущих команд можно сочетанием Alt+..

По умолчанию длина истории небольшая и если нет повышенных требований к безопасности её можно несколько увеличить добавлением в .bashrc строки:

export HISTFILESIZE=5000

Длинная история несколько понижает безопасность системы, особенно если в неё попадают всякие «интересные» команды. Поэтому, на критичных системах размер истории большой делать не стоит. Сбросить историю можно

history -c

Избежать добавления команды в историю можно начав её с пробела. Тогда исполненная инструкция в историю не попадает.

Замена диска в LSI raid-массиве

Время от времени жесткие диски выходят из строя и их необходимо менять. Далее описывается алгоритм такой замены на контроллере LSI MegaRaid SAS9260-4I с помощью оригинальной от производителя утилиты MegaCli.

Жесткие диски в экспандере пронумерованы по снизу вверх, справа налево (по столбцам, т.е. первый столбец снизу вверх идут диски 0-1-2-3 и т.д.). Будем менять 15 сыплющийся диск на исправный 10 в рабочем и здоровом RAID6-массиве. Состояние SMART 15-го диска можно посмотреть командой:

smartctl -d sat+megaraid,15 -a /dev/sdc

Для заменяемого диска находим счетчик перемещенных секторов Reallocated_Sector_Ct далеким от нулевого значения, что означает, что с диском не все в порядке. Информацию об ошибках носителя также можно обнаружить и в состоянии физического диска контроллера:

./MegaCli64 -pdInfo -PhysDrv \[4:15\] -a0

,
где Media Error Count отличен от нуля. 15 в этой команде — id диска на экспандере.

Все работы проводим на исправном массиве. Проверяем, что массив здоров (Optimal):

./MegaCli64 -LDInfo -LAll -aAll | less

Отключаем и вынимаем дефектный жесткий диск:

./MegaCli64 -PDOffline -PhysDrv \[4:15\] -a0
./MegaCli64 -PDPrpRmv -PhysDrv \[4:15\] -a0
./MegaCli64 -PDMarkMissing -PhysDrv \[4:15\] -a0

С помощью -LDInfo -LAll убеждаемся, что нарушен искомый массив и с помощью ./MegaCli64 -pdInfo -PhysDrv \[4:15\] -a0, что диск действительно вне массива.

Теперь необходимо добавить исправный 10-й диск взамен неисправного. Делается это с помощью команды

./MegaCli -PdReplaceMissing -PhysDrv [E:S] -ArrayN -rowN -aN

для которой нам потребуются номера Array и row. Эти числа берутся из вывода

./MegaCli64 -PdGetMissing -a0

Запускаем команду с нужными параметрами, она добавляет диск. Подтверждаем, что диск добавился корректно

./MegaCli64 -pdInfo -PhysDrv \[4:10\] -a0

и в выводимой информации присутствуют правильный номер Disc Group.

Заключительный шаг — запуск ребилда

./MegaCli64 -PdRbld -Start -PhysDrv \[4:10\] -a0

состояние которого можно посмотреть через некоторое время

./MegaCli64 -PdRbld -ShowProg -PhysDrv \[4:10\] -a0

Все вышеприведенное справедливо и для других контроллеров LSA аналогичных моделей. Кроме этого, утилита MegaCli умеет ещё много чего полезного, что легко находится в гугле.