Удаленный шелл с использованием nc

Фундаментальным и очень полезным качеством всех линуксов-юниксов является их модульность и возможность сборки из «кирпичиков» нужных инструментов. Это прекрасно иллюстрируется следующим примером из мануала утилиты netcat. Эта утилита передачи и приема произвольных данных по протоколам tcp/udp позволяет сделать элементарный и полностью рабочий шелл для работы с удалённым хостом. И это только используя эту утилиту и стандартные средства Linux вроде pipe и перенаправления данных.

На удалённой машине создаем трубу

$ rm -f /tmp/f; mkfifo /tmp/f

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

$ cat /tmp/f | /bin/sh -i 2>&1 | nc -l 127.0.0.1 1234 > /tmp/f

В результате получаем упрощённую нешифрованную версию ssh.

Пишем логи с помощью logger

Системное администрирование серверов в большой степени основано на регулярно исполняемых скриптах. Естественно, результат исполнения скриптов нужно проверять и иногда — логировать. Наиболее простой способ это сделать — использовать перенаправления ввода-вывода 2>&1 совместно с &>>. Однако, есть альтернативный (и в чём-то более удобный) способ это сделать, напрямую в syslog, с помощью команды logger. Тогда логирование сводится к командам вроде

some_script.sh 2>&1 | logger -i

Отдельная «поддиректория» для блога в WordPress

По умолчанию, в стоковой установке WordPress формирует постоянные ссылки (permalinks) для постов неотличимые по внешнему виду от статических страниц. Если WP используется как CMS это может быть нежелательно. В случае CMS часто бывает логичней выкладывать статические страницы с пермалинками начиная с корня /, а посты — начиная с некоторого слова, подсказывающего, что пост относится к блогу, например /blog. Это возможно сделать стандартными средствами вордпресса.

Для того, чтобы настроить WP, чтобы он добавлял префикс /blog в начале пермалинков делаем следующее:

  • В админке Settings -> Reading есть возможность настроить статические страницы по умолчанию (front pages) для основного сайта и для блога. Для сайта в случае использования WP как CMS она обычно настроена. Если не настроена, то создаём такую или выбираем из существующих. Для блога — создаем новую пустую и ставим к ней пермалинк /blog.
  • Выбираем созданные front pages соотвественно для основного сайта и для блога.
  • В Settings -> Permalinks меняем формат пермалинков для постов на /blog/%postname%. Предлагаемые по умолчанию настройки RewriteRules в .htaccess подходят и для нашего случая, их не трогаем.
  • Там же меняем базовый URL для категорий и тегов, например на blog/category и blog/tags.
  • Меняем внутренние линки на посты на новые, а также добавляем 301 редиректы со старых постов на новые.

После этого всё работает.

В интернетах находятся и другие how-to по данному вопросу. То, что выше — короткая выжимка из этого.

Хорошие курсы по криптографии

Почти все MOOC при всех их преимуществах грешат одним недостатком — низкий уровень (что напрямую следует из требуемой для рекламы университетов популярности). Тем не менее, на курсере встречаются и действительно хорошие курсы. Например, по шифрованию:
Cryptography I
Cryptography II

Нельзя сказать, что это курсы продвинутого уровня, однако, они понятным языком покрывают обширные и весьма непростые разделы криптографии. Симметричное, несимметричное шифрование, хеши, MAC, HMAC, алгоритмы обмена ключами (Diffie-Hellman), введение в TLS/IPSec и многое другое. Причем, не только фактологически, но с объяснением внутренних связей, причин-следствий. Совмещение теории с практикой в хорошем смысле.
В общем, кто занимается Computer Security, Computer Science эти курсы будут полезны.

ssh/scp под Windows

Несколько решена проблема с доступом ssh/scp из под Windows. Cофтина позволяет монтировать ssh как логический том (sshfs). С её помощью может получиться неплохое решение для удалённых бэкапов из Windows под любые никсы. Жаль, что пока нет решения под Windows 8 и серверную 2012.

Удаление очень больших директорий в Linux

Современные файловые системы вроде ext3/ext4, xfs позволяют создавать в директориях очень большое количество файлов. В ряде случаев (обычно по ошибке или недосмотру) это реализуется на практике и тогда некоторые операции с такой директорией становятся очень медленными. Это касается прежде всего операций, требующих сортировку списка содержимого директории. Такая сортировка, например, происходит при вызове листинга ls, который по умолчанию сортируется, что естественным образом приводит к очень медленному исполнению команды. Также, большая директория очень медленно удаляется rm, поскольку последний формирует листинг.

Чтобы ускорить (а иногда и просто осуществить) удаление большой директории нужно отключить сортировку. Команда rm при удалении берет полностью список файлов, поэтому удалять очень большую директорию «в лоб» с помощью «rm -rf» очень неоптимальный вариант. Большую директорию удобнее удалять частями: листингом без сортировки некоторого количества файлов и их удалением. Сортировка в ls отключается параметром -U, что приводит к такой команде частичного удаления

ls -UA -1 . | head -n 1000 | xargs rm -f

Чтобы удалить содержимое директории полностью и при этом не грузить IO хоста постоянно лучше поставить команду в цикл с небольшими перерывами. Простейший (но не оптимальный и не самый корректный) способ осуществить это

while [ true ]; do ls -UA -1 . | head -n 100 | xargs rm -f 2>/dev/null; sleep 1; done

Альтернативный способ — изменить ionice процесса удаления.

Быстрый способ посмотреть релиз Linux

Наипростейший способ посмотреть информацию о ядре Linux и некоторую информацию о системе это команда uname:

$ uname -a
  Linux sonne 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt2-1 (2014-12-08) x86_64 GNU/Linux

Более подробную информацию о системе можно насобирать в /etc. При этом краткая информация о релизе содержится в файле, который в разных дистрибутивах Linux называется по разному: lsb-release, redhat-release, os-release, centos-release, system-release. Поскольку файл везде оканчивается на -release, то можно не помнить всё это и получать информацию одной командой

cat /etc/*-release

Запуск крона чаще раза в минуту

Наибольшая частота, с которой cron запускается — 1 минута. При администровании серверов бывают ситуации, когда требуется более частый вызов, но конфиг crontab не позволяет этого сделать. Задача решается окольным способом, с помощью вызова нескольких инструкций и использования sleep. Например:

* * * * * /usr/bin/python /usr/local/bin/doit.py
* * * * * sleep 30; /usr/bin/python /usr/local/bin/doit.py

То же можно сделать и в одной строчке, если одну инструкцию исполнять за другой

* * * * * /usr/bin/python /usr/local/bin/doit.py; sleep 30; /usr/bin/python /usr/local/bin/doit.py

Также, можно контролировать возвращаемый инструкцией код и уменьшить количество исполнений в случае ошибки в скрипте. В этом случае точка с запятой меняется на &&.

Защита от DDoS при помощи geoip

Основная задача любой оптимизации состоит в минимизации частоты исполнения медленного кода. Применительно к администрированию web-серверов, медленно генерируемые страницы должны запрашиваться нечасто, или такие страницы необходимо сделать быстро генерируемыми. Для многих «простых» сайтов на известных CMS и обвешанными плагинами любая страница генерируется с использованием значительных ресурсов. Это играет злую шутку на большой мусорной нагрузке, например при умном, но узким DDoS: даже такой сможет обвалить сайт.
В случае, если DDoS идёт из определённых стран, например из Китая и Индии (что происходит в большинстве случаев), то появляется быстрое и эффективное решение для защиты региональных сайтов — фильтр входящих запросов по географии и ответ только на запросы с нужных стран. Тогда, «вредные» запросы не доходят до backend, медленный код не исполняется и ресурсы серверы не тратятся, в результате чего сервер для локальных запросов сервер не падает и обычно даже работает с незаметным замедлением.

Делается это правилом вроде

$IPTABLES -A HTTP -m geoip ! --src-cc RU -j DROP

Перед этим правилом определяется стандартным образом цепочка HTTP (-p tcp --dport 80).

Способ, естественно, не годится на случай широких DDoS, нацеленных на заполнение канала (особенно udp-траффиком). Но для слабых, основанных на генерировании нагрузки, DDoS, он вполне годится.

PS: Естественно geiop модули к iptables должны быть поставлены заранее. Тогда этот способ будет действительно быстрым.

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 для различных частей письма.