Debian, Dojo, Django, Python

Делюсь опытом в описанных технологиях. Блог в первую очередь выполняет роль памяток для меня самого.

Показаны сообщения с ярлыком настройка. Показать все сообщения
Показаны сообщения с ярлыком настройка. Показать все сообщения

Настройка Exim4 / Dovecot в Astra Linux SE 1.5

Настройка почты в Astra Linux 1.5 ALD

Исходные данные и задачи

Необходимо настроить сервер электронной почты, работающий в рамках домена Astra Linux 1.5 SE. Исходные данные:

Параметр Значение
Имя домена local.net
FQDN сервера server.local.net
IP-адрес сервера 192.168.0.1
Маска сети: 255.255.255.0

Настройка сети

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

Отключение wicd
chkconfig wicd off

Прописываем настройки сети в файле /etc/network/interfaces

/etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
allow-hotplug eth0
iface eth0 inet static
    address 192.168.0.1
    netmask 255.255.255.0
    gateway 192.168.0.1
    network 192.168.0.0
    broadcast 192.168.0.255
    dns-nameservers 192.168.0.1
    dns-search local.lan

После этого нужно выполнить перезапуск демона сети:

Перезапуск демона сети
service networking stop && service networking start

В документации к демону networking написано, что команда restart является устаревшей и работает не так, как ожидается.

Необходимо в файле /etc/hosts прописать соответствие FQDN сервера и его IP-адреса, а также задать hostname

/etc/hosts
127.0.0.1    localhost
192.168.0.1 server.local.net server

192.168.0.101 arm01.local.net arm01
192.168.0.102 arm02.local.net arm02
192.168.0.103 arm03.local.net arm03

В файле /etc/hostname меняем краткое имя компьютера server на полное server.local.net, а также изменяем текущее значение системной переменной:

hostname
echo server.local.net > /etc/hostname
hostname server.local.net

Инициализация домена

Действуем согласно официальной инструкции от РусБиТех:

ald-init
ald-init init

Появится уведомление о том, что команда init уничтожит всю базу данных LDAP и Kerberos, будут остановлены и перезапущены службы, и упадет с неба большая звезда, горящая подобно светильнику, и падет на третью часть рек и на источники вод... Отвечаем утвердительно

Попросят ввести пароли для доступа к базе данных Kerberos и пароль администратора Astra Linux Directory. Лучше записать куда-нибудь, потому что понадобится ещё не раз.

Спустя какое-то время на экране появится сообщение:

Успешная инициализация
Astra Linux Directory сконфигурирована.
Сервер ALD активен.
Клиент ALD включен.

Astra Linux Directory сервер успешно инициализирован.

Установка и настройка почтовых сервисов.

Необходимо установить три пакета:

Пакет Описание
exim4-daemon-heavy Передает сообщения и умеет работать с мандатными метками.
dovecot-imapd Умеет отдавать почту клиентам.
dovecot-gssapi Умеет принимать авторизацию на сервере через Kerberos (ALD).

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

Установка и конфигурирование
aptitude install exim4-daemon-heavy dovecot-imapd dovecot-gssapi -y
dpkg-reconfigure exim4-config

Процесс настройки exim4 не очень сложный, но нужно правильно ответить на несколько вопросов.

Вопрос Ответ
Общий тип почтовой конфигурации интернет-сайт; приём и отправка почты напрямую, используя SMTP
Почтовое имя системы: local.net
IP-адреса, с которых следует ожидать входящие соединения SMTP: 192.168.0.1
Другие места назначения, для которых должна приниматься почта: local.net
Домены, для которых доступна релейная передача почты: Оставляем пустым
Машины, для которых доступна релейная передача почты: Оставляем пустым
Сокращать количество DNS-запросов до минимума (дозвон по требованию)? Нет
Метод доставки локальной почты: Maildir формат в домашнем каталоге
Разделить конфигурацию на маленькие файлы? Да

Теперь нужно удалить из каталога /var/mail файл с именем пользователя, созданного при установке системы (у меня обычно administrator).

Удаление лишнего файла
rm /var/mail/administrator

Создадим сервисы ALD для работы с почтой:

Создание сервисов ALD и ключей Kerberos
ald-admin service-add imap/server.local.lan
ald-admin sgroup-svc-add imap/server.local.lan --sgroup=mac
ald-admin sgroup-svc-add imap/server.local.lan --sgroup=mail
ald-admin service-add smtp/server.local.lan
ald-admin sgroup-svc-add smtp/server.local.lan --sgroup=mac
ald-admin sgroup-svc-add smtp/server.local.lan --sgroup=mail
ald-client update-svc-keytab imap/server.local.lan --ktfile="/var/lib/dovecot/dovecot.keytab"
ald-client update-svc-keytab smtp/server.local.lan --ktfile="/var/lib/dovecot/dovecot.keytab"

Указывая имя сервиса, важно помнить, что после слеша указывается то же самое имя сервера, что и в файле /etc/hostname. Если даже в настройках Bind вы потом укажете, что mail.local.net и smtp.local.net являются всего лишь псевдонимами для server.local.net, почта работать не будет, потому что Kerberos очень строго проверяет этот параметр.

После создания файла ключей нужно предоставить доступ к нему для dovecot:

Доступ к файлу ключей
setfacl -m u:dovecot:x /var/lib/dovecot
setfacl -m u:dovecot:r /var/lib/dovecot/dovecot.keytab

Dovecot

Выполняем настройку dovecot. Если убрать все комментарии из файлов, то получится примерно следующее (в тех файлах, где меняли):

/etc/dovecot/dovecot.conf
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap
listen = 192.168.0.1
dict {}
!include conf.d/*.conf
!include_try local.conf
/etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = gssapi
auth_gssapi_hostname = server.local.lan
auth_krb5_keytab = /var/lib/dovecot/dovecot.keytab
!include auth-system.conf.ext

Я не могу в настройку SSL. Отключаем:

/etc/dovecot/conf.d/10-ssl.conf
ssl = no
ssl_cert = </etc/dovecot/dovecot.pem
ssl_key = </dovecot/private/dovecot.pem

Маленькая настройка для корректной работы с почтой - добавляем в файле /etc/dovecot/conf.d/10-master.conf в секцию service auth:

/etc/dovecot/conf.d/10-master.conf
# ...
service auth {
  unix_listener auth-client {
    mode = 0600
    user = Debian-exim
  }
  # ...
}

Немного упрощаем себе и пользователям жизнь, автоматически создавая на сервере каталоги под входящие, отправленные и удаленные письма при первой авторизации (параметр auto = subscribe).

/etc/dovecot/conf.d/15-mailboxes.conf
namespace inbox {
  mailbox Drafts {
    special_use = \Drafts
    auto = subscribe
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Trash {
    special_use = \Trash
    auto = subscribe
  }
  mailbox Sent {
    special_use = \Sent
    auto = subscribe
  }
}

Расположение каталогов внутри /var/mail/%username% можно изменить, сделав более удобным, если в /etc/dovecot/conf.d/10-mail.conf немного изменить параметр mail_location:

/etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/%u:LAYOUT=fs

Exim4

Теперь нужно сделать пару дополнительных настроек Exim4.

/etc/exim4/conf.d/auth/33_exim4-dovecot-kerberos-ald
dovecot_gssapi:
  driver = dovecot
  public_name = GSSAPI
  server_socket = /var/run/dovecot/auth-client
  server_set_id = $auth1 # В конце цифра один, а не маленькая эль

Файл /etc/exim4/conf.d/acl/30_exim4-config_check_rcpt очень большой, поэтому не привожу его полностью. В самом начале нужно добавить в секцию acl_check_rcpt 4 строки, чтобы выглядело примерно так:

Проверка авторизации
acl_check_rcpt:
  deny
    message = "Auth required"
    hosts = *:+relay_from_hosts
    !authenticated = *
  accept:
    hosts = :
    control = dkim_disable_verify
# и так далее

Проверка работоспособности

Заходим от имени пользователя ALD. Запускаем Thunderbird и создаем новую учетную запись. В параметрах IMAP- и SMTP-серверов пишем одно и то же - server.local.net. При нажатии кнопки "Проверка параметров" параметры авторизации должны измениться на Kerberos/GSSAPI. Сохраняем, перезапускаем почтовый клиент. После второго запуска должно загрузиться дерево папок с сервера. Пишем письмо сами себе, если пришло - все хорошо. Если нет - очень внимательно проверяем содержимое всех конфигурационных файлов. Я сам потерял три дня из-за того, что в одном месте пропустил всего одну строку.

Настройка GRUB2 в Debian

Зачем настраивать GRUB 2

Решил я настроить свой GRUB 2, потому что не все его параметры меня устраивают. Ну, например, уменьшить таймаут, увеличить разрешение, в конце концов, поменять фоновую картинку. К чему в итоге пришёл, написано ниже.

Все выполняемые операции требуют привилегий пользователя root.

Настройка разрешения

Первое, что нужно сделать - зайти в консоль самого GRUB'а при запуске. Для этого нужно нажать клавишу c, и, если пароль на загрузчик не установлен, сразу же осуществляется переход к командной строке. Тут вводим одну команду из двух (результат на моём Debian 9 одинаковый):

Команды для определения графических режимов
videoinfo
vbeinfo

Обе команды дают один и тот же результат - список доступных GRUB'у режимов видеоадаптера. Однако, всё не так просто. Дело в том, что при запуске загрузчика загружается видеодрайвер, НО ЭТО НЕ ТОТ ВИДЕОДРАЙВЕР, который даёт полный доступ ко всем режимам видеоадаптера. Таким образом, у меня, например, максимально доступное разрешение не соответствует параметрам монитора, т. е. тут не всё так просто.

В общем, параметры монитора я выяснил, теперь надо было подкрутить /etc/default/grub. Настраивать нужно именно этот файл, поскольку при вызове скрипта update-grub настройки будут взяты оттуда. Ниже привожу только те настройки, которые менял.

/etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=3
GRUB_GFXMODE=1280x1024x32          # Разрешение загрузочного меню GRUB
GRUB_GFXPAYLOAD_LINUX=1920x1080x32 # Передается в параметрах ядра
GRUB_BACKGROUND=/etc/alternatives/desktop-theme/grub/Hexagons-16x9.png
GRUB_DISABLE_OS_PROBER="true"

Краткое описание параметров:

GRUB_DEFAULT Пункт меню по умолчанию
GRUB_TIMEOUT Время в секундах до загрузки пункта по умолчанию
GRUB_GFXMODE Графический режим загрузчика. Можно указать так же значение auto.
GRUB_GFXPAYLOAD_LINUX Разрешение графического режима, которое загрузчик передаст ядру. Если указать правильное значение, можно запускать ОС сразу с нужным разрешением экрана.
GRUB_BACKGROUND Путь к фону загрузчика. Допускается использовать файлы в форматах jpg, png и tga. При необходимости изображение будет отмасштабировано под GRUB_GFXMODE. Если картинки не будет в указанном месте, загрузчик будет запущен в текстовом режиме, без какой-либо графики.
GRUB_DISABLE_OS_PROBER Запретить запуск утилиты osprober, собирающей информацию о других установленных ОС. Поскольку у меня Linux единственная ОС на этом компьютере, могу себе позволить сэкономить немного времени.

После настройки всех параметров обязательно нужно вызвать команду update-grub. Для тех систем, где используется GRUB2, данная команда является символической ссылкой на update-grub2.

Elpy, python-mode и use-package

Emacs - отличный редактор для тех, кто пишет на Python, и есть куча пакетов для поддержки этого языка. Я уже раньше писал, что теперь храню свою конфигурацию и управляю пакетами с помощью use-package, однако, долго не мог найти способ для красивого скрещивания замечательного пакета elpy cо стандартным python-mode.

Решение оказалось не очень сложным, хотя на его поиск пришлось потратить некоторое время. Ниже выкладываю кусок своего init.el.

init.el для elpy + python-mode
(use-package python-mode
  :mode ("\\.py\\'" . python-mode)
  :init(add-hook 'python-mode-hook #'elpy-enable)
  :config
  (use-package elpy
    :bind
    ("M-," . elpy-goto-definition)
    :init
    (elpy-enable)
    (defalias 'workon 'pyvenv-workon)
    :config
    (add-to-list 'company-backends 'elpy-company-backend)
    (elpy-enable))
  (use-package py-autopep8
    :hook
    (python-mode . py-autopep8-enable-on-save))
  (use-package py-isort
    :init
    (add-hook 'before-save-hook #'py-isort-before-save)))

Этот код не делает никакой магии. В общем-то, тут вообще нет ничего интересного.

Самому себе оставляю памятку: в настройках settings.el уже включена автоматическая загрузка недостающих пакетов с помощью use-package. Для всех Python'ьих файлов как major-mode указан python-mode. При его инициализации дополнительно подключаются пакеты elpy, py-autopep8 и py-isort, почти все настройки которых уже вынесены сами знаете куда. Кроме того, каждый пакет при загрузке ставит хуки на определенное действие. Например, автоматическое форматирование или упорядочение импортированных модулей.

Не уверен в том, какую строку с elpy-enable можно удалить, чтобы ничего не сломалось. Сегодня выяснять лень, потом разберусь.

Красивый способ хранения настроек Emacs

Интересный подход к хранению конфигурации Emacs

Интересный способ хранения конфигурации подсмотрел у автора use-package. Если вкратце, то все настройки для конкретных пакетов вынесены в файл settings.el, а вот список используемых пакетов и нюансы взаимодействия между ними описаны целиком и полностью в init.el.

Чтобы далеко не ходить, вот пример кода:

init.el
;;; init.el --- Summary
;;; Commentary:
;;; Main EMACS settings file, load settings from parts.

;;; Code:


;; Added by Package.el.  This must come before configurations of
;; installed packages.  Don't delete this line.  If you don't want it,
;; just comment it out by adding a semicolon to the start of the line.
;; You may delete these explanatory comments.
(package-initialize)

(eval-when-compile(require 'cl))

(require 'package)

(setq package-archives nil)

(add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/") t)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)
(add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/") t)
(add-to-list 'package-archives '("elpy" . "https://jorgenschaefer.github.io/packages/") t)

(setq package-enable-at-startup nil)
(package-initialize nil)

;;; Загрузка и установка пакета use-package, если его нет в системе
(unless(package-installed-p 'use-package)
  (message "EMACS install use-package.el")
  (package-refresh-contents)
  (package-install 'use-package))

(require 'use-package)

;;; Шрифты
(set-face-attribute 'default nil :height 110)
(when (member "DejaVu Sans Mono" (font-family-list))
  (set-face-attribute 'default nil :font "DejaVu Sans Mono"))

;;; Заставляю хоткеи работать и в русской раскладке
(defun cfg:reverse-input-method (input-method)
  "Build the reverse mapping of single letters from INPUT-METHOD."
  (interactive
   (list (read-input-method-name "Use input method (default current): ")))
  (if (and input-method (symbolp input-method))
      (setq input-method (symbol-name input-method)))
  (let ((current current-input-method)
        (modifiers '(nil (control) (meta) (control meta))))
    (when input-method
      (activate-input-method input-method))
    (when (and current-input-method quail-keyboard-layout)
      (dolist (map (cdr (quail-map)))
        (let* ((to (car map))
               (from (quail-get-translation
                      (cadr map) (char-to-string to) 1)))
          (when (and (characterp from) (characterp to))
            (dolist (mod modifiers)
              (define-key local-function-key-map
                (vector (append mod (list from)))
                (vector (append mod (list to)))))))))
    (when input-method
      (activate-input-method current))))

(cfg:reverse-input-method 'russian-computer)


;; Resize windows
(global-set-key(kbd "S-C-") 'shrink-window-horizontally)
(global-set-key(kbd "S-C-") 'enlarge-window-horizontally)
(global-set-key(kbd "S-C-") 'shrink-window)
(global-set-key(kbd "S-C-") 'enlarge-window)

;; Isearch
(global-set-key (kbd "C-M-r") 'isearch-backward-other-window)
(global-set-key (kbd "C-M-s") 'isearch-forward-other-window)

(defun xah-new-empty-buffer()
  "Open a new empty buffer.
  URL `http: // ergoemacs.org / emacs / emacs_new_empty_buffer.html'
  Version 2015 - 06 - 12"
  (interactive)
  (let((ξbuf(generate-new-buffer "untitled")))
  (switch-to-buffer ξbuf)
  (funcall(and initial-major-mode))
  (setq buffer-offer-save t)))

;; Save/close/open
(global-set-key(kbd "C-w") 'kill-this-buffer)
(global-set-key(kbd "C-s") 'save-buffer)
(global-set-key(kbd "C-S-s") 'write-file)
(global-set-key(kbd "C-r") 'revert-buffer)
(global-set-key(kbd "C-a") 'mark-whole-buffer)
(global-set-key(kbd "M-'") 'comment-or-uncomment-region)
(global-set-key(kbd "C-o") 'dired)
(global-set-key(kbd "C-n") 'xah-new-empty-buffer)
(global-set-key(kbd "C-+") 'text-scale-increase)
(global-set-key(kbd "C--") 'text-scale-decrease)

;; Buffers and windows
(global-set-key(kbd "C-") 'next-buffer)
(global-set-key(kbd "C-") 'previous-buffer)
(global-set-key(kbd "C-") 'other-window)

(global-set-key(kbd "M-3") 'delete-other-windows)
(global-set-key(kbd "M-4") 'split-window-horizontally)
(global-set-key(kbd "M-5") 'split-window-vertically)
(global-set-key(kbd "M-6") 'balance-windows)

(global-set-key(kbd "C-f") 'isearch-forward)
(global-set-key(kbd "C-h") 'query-replace)
(global-set-key(kbd "C-S-h") 'query-replace-regexp)

(global-set-key(kbd "M-a") 'execute-extended-command)
(global-set-key(kbd "M-x") 'kill-whole-line)
(global-set-key(kbd "") 'keyboard-quit)

(when(get-buffer "*scratch*")
  (kill-buffer "*scratch*"))

(fset 'yes-or-no-p 'y-or-n-p); ; ; Shortcuts for yea and no

;;; Format file before save
(defun format-current-buffer()
  (indent-region (point-min) (point-max)))
(defun untabify-current-buffer()
  (if (not indent-tabs-mode)
    (untabify (point-min) (point-max)))
      nil)
(add-to-list 'write-file-functions 'untabify-current-buffer)
(add-to-list 'write-file-functions 'delete-trailing-whitespace)

;;; САМЫЙ ВАЖНЫЙ МОМЕНТ - ВЫНЕСЕНИЕ НАСТРОЕК СРЕДЫ В settings.el и загрузка их оттуда
(setq custom-file "~/.emacs.d/settings.el")
(load-file "~/.emacs.d/settings.el")

;;; Теперь просто описание используемых пакетов
;;; Настройки в большинстве случаев подтягиваются из файла settings.el
(use-package airline-themes
  :requires powerline
  :init
  (load-theme 'airline-molokai))

(use-package all-the-icons)

(use-package beacon
  :diminish
  :commands beacon-mode)

(use-package company
  :diminish
  :commands company-mode
  :config
  ;; From https://github.com/company-mode/company-mode/issues/87
  ;; See also https://github.com/company-mode/company-mode/issues/123
  (defadvice company-pseudo-tooltip-unless-just-one-frontend
    (around only-show-tooltip-when-invoked activate)
    (when (company-explicit-action-p)
      ad-do-it))

  (defun check-expansion ()
    (save-excursion
      (if (outline-on-heading-p t)
        nil
          (if (looking-at "\\_>") t
            (backward-char 1)
            (if (looking-at "\\.") t
              (backward-char 1)
              (if (looking-at "->") t nil))))))

  (define-key company-mode-map [tab]
    '(menu-item "maybe-company-expand" nil
    :filter (lambda (&optional _)
      (when (check-expansion)
        #'company-complete-common))))

  (eval-after-load "yasnippet"
    '(progn
      (defun company-mode/backend-with-yas (backend)
        (if (and (listp backend) (member 'company-yasnippet backend))
          backend
          (append (if (consp backend) backend (list backend))
          '(:with company-yasnippet))))
          (setq company-backends
        (mapcar #'company-mode/backend-with-yas company-backends))))
          :init (global-company-mode t))

(use-package company-quickhelp
  :bind
  (:map company-active-map
    ("C-c h" . company-quickhelp-manual-begin)))

(use-package css-mode
  :mode "\\.css\\'")

(use-package elpy
  :mode "\\.py\\'"
  :requires python-mode
  :hook (add-hook 'before-save-hook #'elpy-format-code)
  :init
  (elpy-enable)
  (defalias 'workon 'pyvenv-workon))

(use-package emmet-mode
  :mode  ("\\.html\\'" . emmet-mode)
  :bind
    ("C-j" . emmet-expand-line))

(use-package flycheck
  :commands flycheck-mode
  :init(add-hook 'after-init-hook #'global-flycheck-mode))

(use-package highlight-numbers
  :hook(prog-mode . highlight-numbers-mode))

(use-package ibuffer
  :bind([f2] . ibuffer)
  :init
  (add-hook 'ibuffer-mode-hook #'(lambda ()(ibuffer-switch-to-saved-filter-groups "default"))))

(use-package js2-mode
  :mode ("\\.js\\'" . js2-mode)
  :requires flycheck
  :bind(
    :map js2-mode-map
    ("M-n" . flycheck-next-error)
    ("M-p" . flycheck-previous-error))
  :config
  (add-to-list 'flycheck-disabled-checkers #'javascript-jshint)
  (flycheck-add-mode 'javascript-eslint 'js2-mode)
  (flycheck-mode 1)
  (js2-highlight-unused-variables-mode t))

(use-package json-mode
  :mode (("\\.json\\'" . json-mode)
         ("\\.bowerrc\\'" . json-mode)
         ("\\.jshintrc\\'" . json-mode)))

(use-package json-reformat
  :after json-mode)

(use-package magit
  :bind([f5] . magit-status))

(use-package markdown-mode
  :mode "\\.md\\'")

(use-package monokai-theme
  :init(load-theme 'monokai))

(use-package neotree
  :requires all-the-icons
  :bind
  ([f8] . neotree-toggle))

(use-package powerline)

(use-package py-isort
  :hook
  (add-hook 'before-save-hook 'py-isort-before-save))

(use-package rainbow-delimiters
  :hook
  (prog-mode . rainbow-delimiters-mode))

(scroll-bar-mode -1)

(use-package tide
  :requires js2-mode
  :after js2-mode
  :mode ("\\.js\\'" . tide-mode)
  :hook((before-save-hook . tide-format-before-save)
        (typescript-mode-hook . setup-tide-mode)))

(use-package web-beautify)

(use-package web-mode
  :commands web-mode
  :requires web-beautify
  :mode("\\.phtml\\'" . web-mode)
       ("\\.html\\'" . web-mode)
  :hook (add-hook 'before-save-hook 'web-beautify-html-buffer t t))

(use-package yasnippet
  :after prog-mode
  :defer 10
  :diminish yas-minor-mode
  :mode("/\\.emacs\\.d/snippets/" . snippet-mode)
  :config
  (yas-load-directory (expand-file-name "snippets" user-emacs-directory))
  (yas-global-mode 1))

(use-package yasnippet-snippets
  :after yasnippet)

;;; init.el ends here

Что интересного я взял у автора?

Во-первых, саму организацию хранения описания пакетов. Во-вторых, он отсортировал вызовы use-package по алфавиту. Быстрый поиск не нужен, если можно просто нажать пару раз [PgDn]. В-третьих, он и в файле настроек применил сортировку по алфавиту.

Для тех, кому интересен оригинальный конфиг, его можно найти здесь.

Настройка DNS-сервера bind9 в Debian/Astra Linux

Цели

  • Настройка основного сервера DNS для маленькой локальной сети
  • Сервер должен быть безопасным
  • Сервер должен хранить настройки для конфигурации данной сети
  • Сервер должен обслуживать доменную зону home.net с адресами в подсети 192.168.0/24

Как обычно, если не указано иное, команды выполняются от имени пользователя root.

Исходные данные

Доменная зона home.net
Подсеть 192.168.0/24
Имя основного сервера dc.home.net
IP-адрес сервера имен 192.168.0.1
Имя первого хоста arm01.home.net
IP-адрес первого хоста 192.168.0.101
Имя N-го хоста armN.home.net
IP-адрес N-го хоста 192.168.0.(100+N)

Установка сервера

apt-get install bind9 -y

Сервер установлен, но установка сделана не безопасным способом. Нужно выполнить несколько дополнительных действий, описанных подробнее в Debian Wiki - Bind.

Будем запускать сервер в изолированном окружении:

mkdir -p /var/bind9/chroot/{etc,dev,var/cache/bind,var/run/named}
mknod /var/bind9/chroot/dev/null c 1 3
mknod /var/bind9/chroot/dev/random c 1 8
chmod 660 /var/bind9/chroot/dev/{null,random}
mv /etc/bind /var/bind9/chroot/etc
ln -s /var/bind9/chroot/etc/bind /etc/bind
chown bind:bind /var/bind9/chroot/etc/bind/rndc.key
chmod 775 /var/bind9/chroot/var/{cache/bind,run/named}
chgrp bind /var/bind9/chroot/var/{cache/bind,run/named}

Теперь нужно изменить расположение PIDFILE. Для этого в файле /etc/init.d/bind9 нужно переопределить переменную PIDFILE.

/etc/init.d/bind9
PIDFILE=/var/bind9/chroot/var/run/named/named.pid

Чтобы сервер понимал, что его запускают в изолированном окружении, нужно изменить параметры его запуска, внеся небольшие коррективы в файл /etc/default/bind9

/etc/default/bind9
OPTIONS="-u bind -t /var/bind9/chroot"

Перенастроим логирование rsyslog

echo "\$AddUnixListenSocket /var/bind9/chroot/dev/log" > /etc/rsyslog.d/bind-chroot.conf

Настройка опций сервера

Безопасность

Основные настройки сервера хранятся в файле /etc/bind/named.conf.options (на самом деле сейчас это всего лишь символическая ссылка, но на суть дела это не влияет). Добавим пару параметров для пущей безопасности в разделе options:

/etc/bind/named.conf.options
options {
    ...
    version none; // Скроем версию bind
    allow-query {
        192.168.0/24; // Отвечать будем только на запросы, приходящие из внутренней сети
    };
    ...
}

Включение в конфигурацию новой доменной зоны

В файле /etc/bind/named.conf.default-zones добавим указание на файлы прямой и обратной зоны, чтобы сервер мог обслуживать локальную сеть:

/etc/bind/named.conf.default-zones
...
zone "home.net" in { // Локальная сеть
    type master;
    file "/etc/bind/db.home.net";    // В этом файле будут адреса прямой зоны
};

zone "0.168.192.in-addr.arpa" {      // Так описывается обратная зона, т. е. первые три октета
                                     // записываются в обратном порядке и добавляется .in-addr.arpa
    type master;
    file "/etc/bind/db.0.168.192";   // В этом файле будут адреса обратной зоны
};

Прямая доменная зона

Ниже просто приведу содержимое файла /etc/bind/db.home.net.

/etc/bind/db.home.net
$TTL 3h
@   IN SOA dc.home.net. administrator.home.net. (
; Вместо @ будет подставлено автоматически имя зоны из файла /etc/bind/named.conf.default-zones
    2017092701 ; Это число нужно менять каждый раз при изменении этого файла
               ; Очень удобно взять текущее число и добавить ещё пару цифр для указания ревизии
    3h         ;
    1h         ;
    1w         ;
    1h
)

      IN NS dc.home.net. ; Указываем имя основного DNS-сервера, обслуживающего зону
                         ; Наличие пробела или табуляции в начале строки и точки
                         ; после .net обязательно

dc    IN A  192.168.0.1  ; IP-адрес сервера имен
imap  IN CNAME dc        ; Указываем, что наш DNS-сервер так же отзывается на imap.home.net
smtp  IN CNAME dc        ; и smtp.home.net

arm01 IN A 192.168.0.101
arm02 IN A 192.168.0.102
arm03 IN A 192.168.0.103
arm04 IN A 192.168.0.104
arm05 IN A 192.168.0.105
arm06 IN A 192.168.0.106
arm07 IN A 192.168.0.107
arm08 IN A 192.168.0.108
arm09 IN A 192.168.0.109
arm10 IN A 192.168.0.110

Обратная зона

Создадим файл, на который ссылается обратная зона, и заполним его по образцу:

/etc/bind/db.0.168.192
$TTL 3h
@   IN SOA dc.home.net. administrator.home.net. (
    2017092701 ; Это число тоже нужно менять
    3h         ;
    1h         ;
    1w         ;
    1h
)

      IN NS dc.home.net.

1   IN PTR dc.home.net. ; Наш сервер

101 IN PTR arm01.home.net.
102 IN PTR arm02.home.net.
103 IN PTR arm03.home.net.
104 IN PTR arm04.home.net.
105 IN PTR arm05.home.net.
106 IN PTR arm06.home.net.
107 IN PTR arm07.home.net.
108 IN PTR arm08.home.net.
109 IN PTR arm09.home.net.
110 IN PTR arm10.home.net.

Запуск сервера и проверка работоспособности

Если всё сделано правильно, точки расставлены и IP-адреса указаны верно, можно попробовать запустить наш сервер:

service bind9 start

Если вместо кучи ошибок сервер просто написал, что всё хорошо, можно проверить разрешение имен:

host arm01.home.net
host 192.168.0.9

В обоих случаях сервер должен вернуть информацию о том, на что указывает доменное имя или IP-адрес. Если вместо этого он выдает сообщение об ошибке, самое время проверить корректность конфигурационных файлов. Это делается вызовом следующих несложных команд:

named-checkconf /etc/bind/named.conf
named-checkzone home.net /etc/bind/db.home.net
named-checkzone 192.168.0 /etc/bind/db.0.168.192

Данные утилиты из состава пакета bind9utils укажут на ошибки в конфигурационных файлах.

Клиенты

Существует несколько способов настроить обращение к DNS-серверу на клиентских машинах. По скольку речь идет об операционной системе для социальной группы 'siloviki', выбор инструментальных средств невелик - wicd, /etc/network/interfaces и /etc/resolv.conf.

Первый способ отметаем сразу же, поскольку с wicd довольно много проблем. Не буду останавливаться на них подробно, но обычно первое, что приходится делать на свежеустановленной системе - убрать его из автозагрузки:

service wicd stop
chkconfig wicd off

Можно указать DNS-сервер в настройках сетевых интерфейсов, однако, в этом случае их нужно прописывать для каждого сетевого интерфейса, а я не люблю повторяться. В связи с этим просто откорректируем файл /etc/resolv.conf на клиентских машинах:

domain home.net
search home.net
nameserver 192.168.0.1

Работа в ненулевых мандатных режимах

В данном дистрибутиве реализована мандатная модель разграничения доступа, в том числе к сетевым сервисам. Чтобы обеспечить корректную работу демона named в режимах с мандатной меткой, отличной от нулевой, нужно добавить всего одну строчку в файл /etc/parsec/privsock.conf:

/usr/sbin/named

Управление пакетами в EMACS с помощью use-package

Что такое use-package и как с ним бороться.

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

~/.emacs

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

            ;;; package --- Summary
;;; Commentary:
;;; Main EMACS settings file, load settings from parts.

;;; Code:

(require 'package)

;;; Источники для установки пакетов. Дело в том, что MELPA Stable
;;; содержит не очень свежие версии, поэтому иногда лучше ставить
;;; пакеты из основного репозитория.

(add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/"))
(add-to-list 'package-archives '("melpa"        . "http://melpa.org/packages/"))
(setq package-enable-at-startup nil)
(package-initialize nil)

;;; Если пакет use-package не установлен, его нужно скачать и
;;; установить
(unless (package-installed-p 'use-package)
  (message "EMACS install use-package.el")
  (package-refresh-contents)
  (package-install 'use-package))

;;; Установили, загрузили, указали, что недостающие пакеты нужно
;;; автоматически загружать и устанавливать.
(require 'use-package)
(setq use-package-always-ensure t)

;;; Указываем откуда брать части настроек.
(defconst user-init-dir
  (cond ((boundp 'user-emacs-directory) user-emacs-directory)
        ((boundp 'user-init-directory) user-init-directory)
        (t "~/.emacs.d/")))

;;; Функция для загрузки настроек из указанного файла.
(defun load-user-file (file)
  (interactive "f")
  "Load a file in current user's configuration directory"
  (load-file (expand-file-name file user-init-dir)))

;;; Части конфигурации. Порядок не имеет принципиального значения,
;;; однако я рекомендую некоторые базовые вещи помещать в начало,
;;; чтобы не было необходимости вспоминать базовые команды EMACS
;;; если в результате улучшения сломается один из базовых конфигов.
(load-user-file "neotree.el")
(load-user-file "personal.el")
(load-user-file "themes.el")
(load-user-file "flycheck.el")
(load-user-file "company.el")
(load-user-file "ibuffer.el")
(load-user-file "python.el")
(load-user-file "web.el")
(load-user-file "javascript.el")
(load-user-file "markdown.el")
(load-user-file "json.el")
(load-user-file "yasnippet.el")
(load-user-file "helm.el")
(load-user-file "keyboard.el")
(load-user-file "fonts.el")
(load-user-file "powerline.el")
(load-user-file "elisp.el")

;;; А здесь EMACS хранит настройки, задаваемые через customize
(setq custom-file "~/.emacs.d/customize.el")
(load-user-file "customize.el")

;;; .emacs ends here
        

Половина дела сделана. Настройки размещены в разных файлах, каждый из которых не зависит от других. Вот теперь заживём!

neotree.el

            ;;; Package --- Summary
;;; Commentary:
;;; NeoTree - sidebar for file browsing

;;; Code:

;;; Как я и говорил, пакет будет скачан и установлен автоматически.
(use-package
  neotree
  :bind ([f8] . neotree-toggle)      ;;; Так делается привязка клавиш.
  :init (setq neo-window-width 35)   ;;; Настройки ДО загрузки пакета.
  :config (setq neo-smart-open nil)) ;;; Настройки ПОСЛЕ загрузки пакета.

;;; neotree.el ends here
        

Полагаю, данный пример наглядно показывает, как пользоваться use-package. Продолжим.

personal.el

            ;;; Package --- Summary
;;; Commentary:
;;; User settings for .emacs

;;; Code:

;;; Закрывать *scratch* при запуске.
(kill-buffer "*scratch*")

;;; Цветные скобочки
(use-package
  rainbow-delimiters
  :init (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
        (setq rainbow-delimiters-max-face-count 9))

;;; Scrolling
(setq scroll-step               1) ;; one line
(setq scroll-margin            10) ;; scroll buffer to 10 lines at going to last line
(setq scroll-conservatively 10000)
(setq directory-free-space-args "-Pm")

;; Подсветка результатов поиска и всё такое
(setq search-highlight        t)
(setq query-replace-highlight t)

(setq column-number-mode 1) ;; Номера строк слева
(setq use-dialog-box nil)   ;; Не нужны нам диалоги, будем всё руками делать
(auto-fill-mode -1)         ;; Не знаю, что за параметр, так и не разобрался
(setq-default tab-width          4) ;; Заменить TAB на 4 пробела
(setq-default standart-indent    4) ;; Стандартный отступ - 4 пробела
(setq backup-inhibited t)           ;; Backup'ы тоже делать не будем
(setq auto-save-default nil)        ;; Автосохранение не нужно
(setq scroll-preserve-screen-position 10) ;; Показывать не менее 10 строк на экране

(setq-default c-basic-offset 4 c-indent-level 4 indent-tabs-mode nil) ;; TAB'ы не нужны

(setq-default save-place t) ;; Помнить, где был курсор в прошлый раз

;;; Нажатие Insert больше не включает режим замены
(define-key global-map [(insert)] nil)

;;; Автоформатирование перед сохранением
(defun format-current-buffer()
  (indent-region (point-min)
                 (point-max)))
(defun untabify-current-buffer()
  (if (not indent-tabs-mode)
      (untabify (point-min)
                (point-max)))
  nil)
(add-to-list 'write-file-functions 'untabify-current-buffer)
(add-to-list 'write-file-functions 'delete-trailing-whitespace)

(cua-mode 1)          ;;; Ctrl+C, Ctrl+V! Прямо как в Windows!
(desktop-save-mode 1) ;;; Помнить, какие файлы были открыты в прошлый раз
(fset 'yes-or-no-p 'y-or-n-p) ;;; Вместо yes и no понимать y и n
(global-hl-line-mode 1) ;;; Подсветка текущей строки
(global-linum-mode 1)   ;;; Показывать номера строк всегда
(menu-bar-mode -1)      ;;; А меню - никогда
(scroll-bar-mode -1)    ;;; Скроллбар не нужен
(tool-bar-mode -1)      ;;; Тулбар не нужен

;;; Умные скобочки
(use-package
  smartparens
  :config (smartparens-global-mode 1))

;; Electric pair mode
(electric-pair-mode 1)

;; Иконки в статус-баре
(use-package
  mode-icons
  :config (mode-icons-mode 1))

;; Показывать отступы во всех режимах
(use-package
  indent-guide
  :config (indent-guide-global-mode 1))

;;; Дерево отмены
(use-package
  undo-tree
  :config (global-undo-tree-mode 1))

;;; personal.el ends here
        

python.el

Очень интересный конфиг получается для Python.

            ;;; Package --- Summary
;;; Commentary:
;;; Settings for Python

;;; Code:

(defun annotate-pdb()
  (interactive)
  (highlight-lines-matching-regexp "import ipdb")
  (highlight-lines-matching-regexp "import pdb")
  (highlight-lines-matching-regexp "set_trace()")
  (highlight-regexp "^TODO ")
  (highlight-phrase "FIXME"))

(use-package
  python
  :mode ("\\.py'" . python-mode)
  :init (progn
          (defalias 'python2-mode 'python-mode)
          (defalias 'python3-mode 'python-mod))
  :config (setq-default py-separator-char 47) ;; Use spaces instead tab
  (setq-default python-indent-offset 4) ;; 4 spaces instead 2 for python-mode
  )

(use-package
  company-anaconda
  :ensure t
  :init (add-to-list 'company-backends 'company-anaconda))

(use-package
  py-autopep8
  :init (progn (add-hook 'python-mode-hook 'py-autopep8-enable-on-save)))

(use-package
  anaconda-mode
  :commands anaconda-mode
  :diminish anaconda-mode
  :init (progn (add-hook 'python-mode-hook 'anaconda-mode)
               (add-hook 'python-mode-hook 'eldoc-mode)
               (add-hook 'python-mode-hook 'annotate-pdb)))

(use-package
  pyvenv
  :config (defalias 'workon 'pyvenv-workon))

(use-package
  py-isort
  :config (setq py-isort-options '("-sl"))
  :init (progn (add-hook 'python-mode-hook 'py-isort-before-save)))

(use-package
  company-anaconda
  :config (add-to-list 'company-backends 'company-anaconda))

;;; python.el ends here 
        

Не уверен, что нужно что-то тут объяснять, но на всякий случай свой company.el тоже выставляю напоказ.

company.el

Этот модуль отвечает за подсказки и автозавершение. Он новее, чем autocomplete, и активно развивается. Большая часть плагинов дополнения сейчас пишется именно под него.

            ;;; Package --- Summary
;;; Commentary:
;;; Settings for company

;;; Code:

(use-package
  company
  :diminish company-mode
  :config (setq company-backends (remove 'company-ropemacs company-backends) company-tooltip-limit
                20 company-tooltip-align-annotations t)
  (global-company-mode 1))

;;; company.el ends here
        

Настройка сети в Astra Linux

Все выполняемые операции требуют привилегий пользователя root.

Astra Linux использует для конфигурирования сетей собственную утилиту wicd. В общем, она довольно удобна, но у неё есть фатальный недостаток - её писали не мы сеть не будет работать до авторизации пользователя в системе. Для обычных компьютеров в этом нет ничего страшного, однако, для сервера это большая проблема, так как иногда его приходится перезагружать по SSH.

Пусть компьютеры будут находиться в сети с адресами 192.168.0.XXX, где вместо XXX - число от 1 до 254.

Настройка осуществляется путем правки файла /etc/network/interfaces. Каждый сетевой интерфейс (сетевая карта, хотя это не совсем точное название) настраивается отдельно. Настройки для сервера выглядят так:

/etc/network/interfaces
auto lo eth0

iface lo inet loopback

iface eth0 inet static
    address 192.168.0.1
    netmask 255.255.255.0
    gateway 192.168.0.1         # В качестве шлюза - наш сервер с IP=1
    network 192.168.0.0         # Указываем сеть, это обязательно для работы в составе ALD
    broadcast 192.168.0.255     # Сервер ALD начиная с Astra 1.5 выводит ошибку, если не видит
                                # этого параметра в настройках сети.
    dns-nameservers 192.168.0.1 # Тут через пробел можно перечислить ВСЕ DNS-серверы сети
    dns-search DOMAIN.NET       # Имя домена ALD

Первая строчка auto lo eth0 указывает, какие интерфейсы должны быть запущены при загрузке ОС. Отмечу, что локальная петля lo должна присутствовать там в любом случае.

Пропустим описание локальной петли и сразу перейдем к сетевому интерфейсу.

iface Ключевое слово, говорящее о том, что дальше будет описание сетевого интерфейса
eth0 Указываем, что данный сетевой интерфейс должен быть привязан к сетевой карте eth0. Посмотреть список карт можно командой: lshw -class network
inet Указываем, что это будет настройка сети.
static При этом все настройки будут указаны вручную.
address IPv4-адрес компьютера
netmask Маска подсети.
gateway Шлюз, т. е. IP-адрес, через который идёт подключение к интернету. Обычно на сервере указывают адрес, выданный провайдером, но в нашем случае (закрытый от мира сегмент) пусть будет 192.168.150.1, т. е. компьютер обращается сам к себе.
dns-nameservers Список разделенных пробелами IP-адресов DNS-серверов. Полезно при разворачивании ЕПП под управлением Astra Linux и настройке приложения bind.

На клиентских компьютерах настройки следует выполнить аналогичным образом, меняя только четвёртый октет в поле address.

На этом настройка не заканчивается. Теперь нужно отключить автозапуск встроенных утилит и остановить уже запущенный экземпляр службы wicd, после чего перезапустить службу поддержки сети.

service wicd stop
chkconfig wicd off
rm /etc/xdg/autostart/fly-admin-wicd.desktop
service networking restart

Если на одной сетевой карте по каким-то причинам нужно иметь 2 или более IP-адресов, настройки делаются следующим образом:

/etc/network/interfaces
auto lo
iface lo inet loopback # Кстати, удалять интерфейс локальной петли не стоит,
                       # некоторые службы от этого сходят с ума и начинают
                       # выдавать весьма странные ошибки

auto eth0:0
allow-hotplug eth0:0
iface eth0:0 inet static
    address 192.168.0.1
    netmask 255.255.255.0
    network 192.168.0.0
    gateway 192.168.0.1
    broadcast 192.168.0.255
    dns-nameservers 192.168.0.1 192.168.0.2
    dns-search DOMAIN.NET

auto eth0:1
allow-hotplug eth0:1
iface eth0:1 inet static
    address 10.2.12.54      # Адрес, маска и все остальные параметры в этой
    netmask 255.255.255.128 # секции были придуманы за 20 секунд, поэтому
    network 10.2.12.0       # не ручаюсь за правильность заполнения. Гуглите
    gateway 10.2.12.1       # маску подсети для этого случая самостоятельно.
    broadcast 10.2.12.255
    dns-nameservers 8.8.8.8
    dns-search GOOGLE.RU

Посмотреть настройку сети в Debian более подробно можно на официальной Wiki-странице или её несколько устаревшей русской версии

Хоткеи в EMACS

Запись была обновлена 11.09.2016 г. Исправлены ошибки в разметке, из-за которых не выводились на экран некоторые элементы кода.

Основы

Я долгое время пользовался пакетом ergoemacs и был доволен, однако, со временем он стал обрастать функциями, которые мне стали не нужны, а иногда откровенно глючили на моём самосборном EMACS'е. Пришлось изучить, как настраиваются хоткеи в редакторе.

Во-первых, вместо привычных Ctrl, Alt и Shift в EMACS для обозначения модификаторов используются другие значения:

C Ctrl
M Alt
S Shift

Ни в одном руководстве по EMACS вы не найдете записи типа Ctrl+S - там будет написано C-S, хотя по сути эти две записи идентичны.

Во-вторых, клавиши, которые нажимаются вместе, записываются через дефис.

Третье, регистр имеет значение.

Последнее, что нужно знать о клавиатурных комбинациях EMACS - некоторые команды состоят из последовательного нажатия разных клавиатурных комбинаций, например, выход из редактора выглядит так: C-x C-c, что означает следующее:

  • Сначала нажимаем Ctrl+X
  • Теперь нажимаем Ctrl+C

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

К делу!

Перед тем, как использовать какую-либо клавиатурную комбинацию, следует убедиться, что она уже не привязана к какому-либо действию, либо освободить её от этой привязки. Ниже показано, как удалить привязку команды к комбинации и тут же связать её с новой командой:

(global-unset-key (kbd "C-S-c C-S-c"))
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
Обратите внимание, что привязывать к комбинациям следует только те команды, про которые "знает" EMACS, иначе при запуске он будет выдавать ошибки в конфигурации.

С простыми клавишами разобрались, добавим функциональные:

(require 'neotree)
(require 'ibuffer)
(require 'magit)
(require 'dired)

(global-set-key [f2] 'ibuffer)
(global-set-key [f3] 'dired)
(global-set-key [f8] 'neotree-toggle)
(global-set-key [f10] 'magit-status)

Теперь посмотрим, как описываются стрелки:

;; Resize windows
(global-set-key (kbd "S-C-<left>") 'shrink-window-horizontally)
(global-set-key (kbd "S-C-<right>") 'enlarge-window-horizontally)
(global-set-key (kbd "S-C-<down>") 'shrink-window)
(global-set-key (kbd "S-C-<up>") 'enlarge-window)

Можно ли сделать с полученными знаниями что-то полезное? Да! Давайте удалим ergoemacs и начнем вместо него использовать свои собственные комбинации!

;;; Package --- Summary
;;; Commentary:
;;; Keybindings for non-latin layout

;;; Code:

(setq initial-major-mode (quote text-mode))

(defun cfg:reverse-input-method (input-method)
  "Build the reverse mapping of single letters from INPUT-METHOD."
  (interactive
   (list (read-input-method-name "Use input method (default current): ")))
  (if (and input-method (symbolp input-method))
      (setq input-method (symbol-name input-method)))
  (let ((current current-input-method)
        (modifiers '(nil (control) (meta) (control meta))))
    (when input-method
      (activate-input-method input-method))
    (when (and current-input-method quail-keyboard-layout)
      (dolist (map (cdr (quail-map)))
        (let* ((to (car map))
               (from (quail-get-translation
                      (cadr map) (char-to-string to) 1)))
          (when (and (characterp from) (characterp to))
            (dolist (mod modifiers)
              (define-key local-function-key-map
                (vector (append mod (list from)))
                (vector (append mod (list to)))))))))
    (when input-method
      (activate-input-method current))))

(cfg:reverse-input-method 'russian-computer)

(require 'neotree)
(require 'ibuffer)
(require 'magit)
(require 'dired)

(global-set-key [f2] 'ibuffer)
(global-set-key [f3] 'dired)
(global-set-key [f8] 'neotree-toggle)
(global-set-key [f10] 'magit-status)

;; Multiple cursors
(global-unset-key (kbd "C-S-c C-S-c"))
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)

;; Resize windows
(global-set-key (kbd "S-C-<left>") 'shrink-window-horizontally)
(global-set-key (kbd "S-C-<right>") 'enlarge-window-horizontally)
(global-set-key (kbd "S-C-<down>") 'shrink-window)
(global-set-key (kbd "S-C-<up>") 'enlarge-window)

(defun xah-new-empty-buffer ()
  "Open a new empty buffer.
URL `http://ergoemacs.org/emacs/emacs_new_empty_buffer.html'
Version 2015-06-12"
  (interactive)
  (let ((ξbuf (generate-new-buffer "untitled")))
    (switch-to-buffer ξbuf)
    (funcall (and initial-major-mode))
    (setq buffer-offer-save t)))

;; Save/close/open
(global-set-key (kbd "C-w") 'kill-this-buffer)
(global-set-key (kbd "C-s") 'save-buffer)
(global-set-key (kbd "C-S-s") 'write-file)
(global-set-key (kbd "C-r") 'revert-buffer)
(global-set-key (kbd "C-a") 'mark-whole-buffer)
(global-set-key (kbd "M-'") 'comment-or-uncomment-region)
(global-set-key (kbd "C-o") 'dired)
(global-set-key (kbd "C-n") 'xah-new-empty-buffer)
(global-set-key (kbd "C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)

;; Buffers and windows
(global-set-key (kbd "C-<next>") 'next-buffer)
(global-set-key (kbd "C-<prior>") 'previous-buffer)
(global-set-key (kbd "C-<tab>") 'other-window)

(global-set-key (kbd "M-3") 'delete-other-windows)
(global-set-key (kbd "M-4") 'split-window-horizontally)
(global-set-key (kbd "M-5") 'split-window-vertically)
(global-set-key (kbd "M-6") 'balance-windows)

(global-set-key (kbd "C-f") 'isearch-forward)
(global-set-key (kbd "C-h") 'query-replace)
(global-set-key (kbd "C-S-h") 'query-replace-regexp)

(global-set-key (kbd "M-a") 'execute-extended-command)
(global-set-key (kbd "M-x") 'kill-whole-line)
(global-set-key (kbd "<esc>") 'keyboard-quit)

(setq x-select-enable-clipboard t)

;; Highlight search resaults
(setq search-highlight        t)
(setq query-replace-highlight t)

;;; keyboard.el ends here

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

Django 1.8, Python 3, WSGI и Gunicorn

Введение

В данной статье рассказывается, как можно запустить приложение на Django и Python 3 под WSGI. Способ не претендует на звание самого лучшего, замечания по настройке и прочим нюансам приветствуются.

Структура каталогов

Следует создать в каталоге /var/www подкаталог для нашего проекта. Пусть сегодня он будет называться talos. В нём нужно будет создать каталоги для размещения статичных файлов, файлов, загружаемых пользователями, и логов.

От имени www-data
cd /var/www
mkdir talos
cd talos/
mkdir static media log

Сам проект будет расположен в виртуальном окружении, которое будет создано чуть позже.

Создание файла запуска

Здесь же, в каталоге /var/www/talos, создадим файл run.bash, который будет запускать приложение, передавая ему нужные параметры.

/var/www/talos/run.bash
   #!/bin/bash

NAME="talos"                                # Название приложения
DJANGODIR=/var/www/.virtualenvs/talos/talos # Директорая проекта - путь к виртуальному окружению
                                            # плюс папка с проектом
SOCKFILE=/var/www/sockets/talos.sock        # Тут будет лежать сокет
USER=www-data                               # От чьего имени запускается
GROUP=www-data                              # Группа для запуска
NUM_WORKERS=3                               # Кол-во воркеров, обычно число ядер * 2 + 1
DJANGO_SETTINGS_MODULE=talos.settings       # Откуда брать настройки
DJANGO_WSGI_MODULE=talos.wsgi               # Имя wsgi-файла для запуска

echo "Starting $NAME as `whoami`"

# Активация окружения
cd $DJANGODIR
source ../bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Если папки для сокета нет, её надо создать
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Запуск через gunicorn с передачей параметров
exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug \
  --log-file=/var/www/talos/log/talos.log
  

Создание виртуального окружения

Последние версии Django написаны на Python 3, да и вообще использовать Python 2 в 2015 году - дурной тон. Ставим нужные пакеты, если их ещё нет:

Установка пакетов
apt-get install python3-dev virtualenvwrapper -y

Первый пакет нужен для сборки пакетов, поставляемых в исходных кодах (lxml, psycopg2, pillow), второй - для удобного управления виртуальными окружениями. Пакеты установлены, пользователь www-data в системе. Пришло время создать окружение и поставить нужные пакеты:

Создание окружения, установка пакетов
mkvirtualenv talos --python=/usr/bin/python3
workon talos

В результате в каталоге для виртуальных окружений (у каждого пользователя свой, по умолчанию называется .virtualenvs) будет создан подкаталог talos. В нём будут размещены необходимые для работы с окружением скрипты и несколько других каталогов. Разместим наш проект внутри каталога /var/www/.virtualenvs/talos.

Далее следует поставить в окружение все необходимые пакеты, требуемые для запуска проекта, а так же пакет gunicorn. При необходимости стоит так же обновить pip, его последние версии умеют кэшировать скачанные пакеты.

Не забудьте создать статику и при необходимости подкорректировать файл настроек приложения.

Запуск через supervisor

Если supervisor ещё не установлен, пришло время это сделать:

Установка supervisor
apt-get install supervisor -y

Настройки хранятся в каталоге /etc/supervisor. Главный файл называется supervisor.conf, файлы для запуска приложений следует расположить в каталоге /etc/supervisor/conf.d/, указав расширение .conf. В нашем случае файл будет лежать по пути /etc/supervisor/conf.d/talos.conf

/etc/supervisor/conf.d/talos.conf
[program:talos]
command=/var/www/talos/run.bash
user=www-data
group=www-data

autostart=true
autorestart=true

redirect_stderr=true
stdout_logfile=/var/www/talos/log/supervisor.log

Когда файл будет создан, следует обновить данные Supervisor'а:

supervisorctl update

При необходимости перезапустить то или иное приложение следует вызывать не перезапуск системной службы supervisor, а давать команды supervisorctl:

Управление Supervisor'ом
supervisorctl update        # Перечитать файлы конфигации приложений
supervisorctl start talos   # Запустить приложение talos
supervosorctl stop talos    # Остановить приложение talos
supervisorctl restart talos # Перезапуск приложения talos
supervisorctl status        # Посмотреть статус всех приложений
supervisorctl ДЕЙСТВИЕ all  # Выполнить ДЕЙСТВИЕ со всеми приложениями, например, перезапуск

Если всё сделано правильно, приложение будет запущено, а в каталоге /var/www/sockets/ появится файл сокета talos.sock (как было настроено в файле run.bash).

Подключение к nginx

Всё, что нужно теперь сделать - указать nginx путь к сокету и откуда брать статику для проекта. В общем-то, всё довольно просто. Nginx лучше ставить из официального репозитория проекта, а не из Debian'овского, там пакет не обновляется годами.

apt-get install nginx -y

Все настройки в каталоге /etc/nginx, главный файл - nginx.conf, настройки для сайтов в .conf-файлах, лежащих в каталоге /etc/nginx/conf.d/.

Создадим файл настроек, общих для всех сайтов: /etc/nginx/proxy_params.conf:

/etc/nginx/proxy_params.conf
proxy_redirect                          off;
proxy_set_header Host                   $http_host;
proxy_set_header X-Real-IP              $remote_addr;
proxy_set_header X-Url-Scheme           $scheme;
proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto      $scheme;
client_max_body_size                    20m;
client_body_buffer_size                 1m;
proxy_buffering                         off;
proxy_send_timeout                      180;
proxy_read_timeout                      180;
proxy_connect_timeout                   180;
proxy_buffer_size                       4k;
proxy_buffers                           32 32k;
proxy_busy_buffers_size                 64k;
proxy_temp_file_write_size              1m;
add_header X-Frame-Options "SAMEORIGIN";

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

/etc/nginx/conf.d/talos.conf
upstream talos {
    server unix:/var/www/sockets/talos.sock fail_timeout=0;
    keepalive 30;
}

server {
    listen 80;
    server_name talos.lo;
    keepalive_timeout 3;
    access_log off;
    error_log /var/www/talos/log/nginx_error.log crit;

    location / {
        proxy_pass http://talos/;
        include /etc/nginx/proxy_params.conf;
    }

    location /static/ {
        alias /var/www/talos/static/;
        expires 3d;
    }

    location /media/ {
        alias /var/www/talos/media/;
           expires 3d;
    }

    location ~* \.(7z|jpg|jpeg|gif|png|ico|css|bmp|swf|js|html|txt|doc|docx|pdf|rar|xls|xlsx|zip)$ {
        root /var/www/talos/;
        expires 3d;
        add_header Cache-Control: public;
        access_log off;
        error_log /var/www/talos/log/nginx_static_error.log;
    }
}

Перезапустите nginx, тобы он подхватил новый конфигурационный файл. На этом всё.

Обо всех ошибках или дополнения прошу писать мне на почту dunmaksim@yandex.ru

Минимальная настройка SSH в Debian 7 Wheezy

Статья обновлена 18.12.2017, исправлены опечатки и ошибка с перемещением публичного ключа вместо приватного.

Цели

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

Все действия выполняются от имени пользователя root, если не указано иное.

Установка пакетов

Установить сервер OpenSSH в Debian очень просто:

Установка
apt-get install openssh-server -y

Вместе с самим сервером ставится несколько зависимостей. В моём случае (Debian 7.5) это openssh-client и ncurses-term.

Служба сервера sshd будет автоматически запущена после установки. Обращаться к ней в терминале следует по имени ssh, например (запуск, остановка, перезапуск):

Установка
service ssh start
service ssh stop
service ssh restart

Увеличение длины серверного ключа

По умолчанию длина ключа OpenSSH в Debian 7 - 768 бит, что явно недостаточно. Следует указать значение не ниже 2048 и сгенерировать ключи заново!

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

  1. Переходим в каталог /etc/ssh
  2. Изменяем в sshd_config значение параметра ServerKeyBits с 768 на 2048.
  3. Удаляем старые ключи командой

    rm -rf ssh_host_*
  4. Выполняем перегенерацию ключей сервера (служба будет перезапущена автоматически):

    dpkg-reconfigure openssh-server

Минимальная настройка

Все найстроки сервера OpenSSH хранятся в файле /etc/ssh/sshd_config. Откроем его для редактирования и рассмотрим минимально необходимые опции, которые не рекомендуется трогать либо наоборот настоятельно рекомендуется изменить.

  • Port 22 - лучше всего сразу сменить порт на другой, однако, номер порта желательно выбрать больше 1024, чтобы случайно не создать конфликт с какой-нибудь другой программой, работающей на этом порту.
  • ListenAddress 0.0.0.0 - по умолчанию закомментировано. Можно указать, какой интерфейс должен слушать наш сервер. Если на сервере несколько интерфейсов, один из которых торчин наружу, например, предоставляет доступ к WEB-серверу, а работа с сервером будет производиться только из внутренней сети, я советую указать здесь адрес сервера во внутренней сети, чтобы заблокировать доступ из Интернета.
  • UsePrivilegeSeparation yes - ни в коем случае не отключать разделение привилегий!
  • LoginGraceTime 120 - время в секундах, в течение которого следует авторизоваться на сервере. По истечении указанного интервала сервер автоматически разорвёт соединение.
  • PermitRootLogin yes - настоятельно рекомендую сменить на no! Пользователь root не должен подключаться к серверу! Для выполнения команд, требующих повышения привилегий, следует использовать sudo!
  • PubkeyAuthentication yes - включаем, т.к. дальше будет рассматриваться использование публичных ключей для подключения к серверу.
  • AuthorizedKeysFile %h/.ssh/authorized_keys - следует раскомментировать для доступа с помощью открытых ключей шифрования. По умолчанию эта настройка указывает на то, что открытые ключи каждого пользователя следует искать в его домашнем каталоге, в файле authorized_keys, лежащем в подкаталоге .ssh.

Изменив эти минимальные настройки, перезапустите службу ssh.

Проверка работоспособности

Попробуйте подключиться к своему серверу с него самого:

ssh user@localhost

где user - ваш настоящий логин в системе.

При самом первом подключении ваш SSH-клиент будет спрашивать, следует ли доверять указанному хосту и принять от него ключ шифрования. Отвечаем yes (нужно написать слово полностью). Сервер предложит ввести пароль для авторизации в системе. Вводим его. Если всё правильно, вы окажетесь в консоли, где сможете вводить команды.

Генерация и размещение ключей

Генерация ключей

При шифровании с открытым ключом потребуется создать пару из двух ключей - открытого и закрытого. В *nix-системах стандартным средством для их генерации является программа ssh-keygen. Запуск её с различными параметрами приводит к созданию различных ключей. В нашем случае будет использован минимум настроек.

Выполните указанную ниже команду для создания ключа длиной 2048 бит и с комментарием "New generated key". Права root не требуются. Я советую добавить комментарий для ключа - в этом случае при подключении с его помощью в логах сервера будет отображаться этот комментарий. Можете ввести сюда свои имя и фамилию.

Генерация пользовательских ключей
ssh-keygen -b 2048 -C "New generated key"

Система предложит указать имя для новых файлов. Для примера будем использовать new_key

Затем будет задан вопрос, какая парольная фраза будет использоваться для ключа. Если не заполнять это поле, то ключ не будет защищён паролем. Рекомендую ввести сюда что-нибудь. После первого ввода парольной фразы будет предложено ввести её ещё раз.

После этого в текущем каталоге (если вы ввели имя файла выше) будут созданы два файла - new_key и new_key.pub

Файл new_key - это закрытый ключ. Его нужно сохранить в надёжное место на вашем компьютере и не давать никому. Как правило, его кладут в домашнем каталоге в папку .ssh под именем id_rsa, при этом права на файл должны быть 0600:

Изменение прав доступа к ключу
mv new_key ~/.ssh/id_rsa
chmod 0600 ~/.ssh/id_rsa

Если права будут указаны неправильно, могут возникнуть проблемы. Например, утилита Seahorse из комплекта Gnome при попытке добавить этот ключ в хранилище будет запрашивать пароль, но при нажатии кнопки "Сохранить" выдаст ошибку.

Файл new_key.pub - это открытый ключ. Его также следует сохранить на вашем компьютере, однако, именно его следует распространять на серверах, к которым вы будете подключаться.

Размещение ключей на целевой системе

Если в домашнем каталоге пользователя не существует каталога .ssh, создайте его, а внутри него разместите пустой файл authorized_keys.

Размещение ключей на сервере
cd ~
mkdir .ssh
cd .ssh/
touch authorized_keys

Теперь в этот файл мы добавим наш открытый ключ с помощью стандартной команды >>

cat ~/new_key.pub >> authorized_keys

Теперь следует скопировать закрытый ключ на ваш компьютер. Его мы будем использовать для подключения к нашему серверу.

Использование закрытых ключей и Putty

Формат закрытых ключей, используемых программой Putty, несколько отличается от того, который используется в *nix-системах. Тем не менее, в комплекте идёт программа puttygen. Запустите её.

В меню выберите пункт Conversion, а в нём - Import key.

Найдите ваш закрытый ключ и откройте его.

Если ранее вы указали парольную фразу, сейчас её нужно будет ввести для открытия ключа.

Нажмите кнопку Save private key

Дайте подходящее имя закрытому ключу и сохраните его куда-нибудь. Как видите, формат файла изменился - теперь он ppk

Создайте в Putty новое подключение. В настройках найдите пункт Auth. На этой странице в поле Private key file for authentication выберите сохранённый ключ.

Сохраните подключение.

Нажмите Open

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

Использование ключей для авторизации не отменяет ввода пароля пользователя при вызове команды sudo!

Настройка Redmine на Debian 7

Установка и настройка Redmine в Debian 7 (nginx + postgresql + thin)

В данной статье рассматривается установка и настройка Redmine версии 1.x в Debian 7 с помощью apt. Если вам нужна инструкция по настройке Redmine версии 2.x, то эта статья не для вас.

Краткое содержание:

  • Введение
  • Список используемых пакетов.
  • Порядок установки и настройки пакетов.
    • Предварительная настройка PostgreSQL
    • Установка пакетов
    • Создание базы данных
  • Увязка Redmine с nginx через thin.

Введение

Redmine - система для управления проектами. Если говорить простым языком, эта система служит для того, чтобы можно было вести учёт обращений, заявок, багрепортов и известных проблем о каждом продукте компании. Помимо этого в системе есть встроенная Wiki, база знаний, диаграммы Ганта, разделение по проектам и ролям и т.д. Если вы работаете в фирме, которая занимается разработкой ПО, то этот или аналогичный продукт вам жизненно необходим. С помощью Redmine можно оперативно отслеживать ход работы, исправления обнаруженных ошибок и т.д. В общем, на выходе получается целый комбайн.

Список используемых пакетов

Для работы Redmine требуется установка Ruby On Rails. К нашему удовольствию разработчики Debian'а включили все необходимые пакеты в список зависимостей, значительно упростив установку. Исключение сделано лишь для двух пакетов - сервер, который будет запускать Redmine, и пакет для соединения с БД.

Ниже приведён минимальный список пакетов, которые нам потребуются:

  • thin - сервер для запуска продуктов, написанных на Ruby
  • redmine - сама система
  • ruby-pg - драйвер для подключения программ, написанных на Ruby On Rails, к СУБД PostgreSQL.

Установка Ruby будет выполнена автоматически

Предварительная настройка базы в PostgreSQL

Запустим интерпретатор psql от имени суперпользователя postgres:

sudo su -c psql postgres

Создадим нового пользователя и базу данных, к которой он будет иметь полный доступ, после чего закроем интерпретатор:

CREATE ROLE redmine WITH PASSWORD 'redmine' LOGIN;
CREATE DATABASE redmine WITH OWNER redmine;
\q

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

Установка пакетов и настройка параметров Redmine

Установка пакетов

Для установки всех необходимых пакетов нужно от имени root выполнить команду:

apt-get install redmine ruby-pg thin -y

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

Настройка доступа к БД

Перейдём в каталог /etc/redmine/default

cd /etc/redmine/default

Здесь находится всего два файла - database.yml и session.yml. Нам нужен только первый, отвечающий за настройки доступа к БД.

Содержимое database.yml:

production:
  adapter: postgresql
  database: redmine
  host: localhost
  port:
  username: redmine
  password: redmine
  encoding: utf8

Все настройки, полагаю, понятны без комментариев. Отмечу только, что первая строка, production:, указывает на то, что данная конфигурация должна использоваться при запуске сервера в рабочем режиме. Также доступны режимы development и test.

Настройка сервера thin

Теперь нужно настроить thin. В Debian 7 при установке thin ставятся сразу две его версии, 1.8 и 1.9.1, мы будем использовать последнюю. Переходим в каталог настроек и создаём файл для запуска Redmine:

cd /etc/thin1.9.1/
touch redmine.yml
chmod 644 redmine.yml

Открываем созданный файл в любимом текстовом редакторе и вносим туда следующие данные:

---
chdir: /usr/share/redmine
environment: production
timeout: 30
log: /var/log/thin/redmine.log
pid: /var/run/redmine/redmine.pid
max_conns: 1024
max_persistent_conns: 512
require: []

wait: 30
socket: /var/run/redmine/redmine.sock
daemonize: true
user: www-data
group: www-data
servers: 1
prefix: /redmine

socket указывает путь и имя сокетов, создаваемых thin при запуске Redmine.

Параметр servers указывает, сколько серверов следует запустить. Другими словами, он определяет количество сокетов, которые будут созданы в указанном каталоге. К имени сокета, указанному выше, будет добавлен порядковый номер.

Servers: 1

ls /var/run/redmine
redmine.sock.0

Servers: 2

ls /var/run/redmine
redmine.sock.0
redmine.sock.1

prefix указывает на то, по какому адресу на сервере будут обрабатываться запросы к Redmine. Поясню на примере. Допустим, адрес нашего сайта - http://sharkon.ru/ . При переходе к этому адресу человек будет получать главную страницу нашего сайта. Пусть при переходе по ссылке http://sharkon.ru/redmine/ открывается Redmine. Именно за часть адреса, идующую после указания доменного имени, отвечает этот параметр. Если сайт используется для внутренних нужд и не торчит наружу, можно дать ему, например, такое доменное имя: http://redmine.lo/ , прописав в настройках сервера DNS, к какой машине в локальной сети нужно подключаться для работы с этим сайтом. В этом случае строку с параметром prefix следует удалить из файла конфигурации полностью!

Настройка nginx.

В каталоге /etc/nginx/ следует создать файл proxy_params.conf. На моих серверах он выглядит примерно так:

proxy_redirect                          off;
proxy_set_header Host                   $http_host;
proxy_set_header X-Real-IP              $remote_addr;
proxy_set_header X-Url-Scheme           $scheme;
proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto      $scheme;
client_max_body_size                    20m;
client_body_buffer_size                 1m;
proxy_buffering                         off;
proxy_send_timeout                      180;
proxy_read_timeout                      180;
proxy_connect_timeout                   180;
proxy_buffer_size                       4k;
proxy_buffers                           32 32k;
proxy_busy_buffers_size                 64k;
proxy_temp_file_write_size              1m;
add_header X-Frame-Options "SAMEORIGIN";

При необходимости измените настройки, исходя из параметров вашего сервера. Указанные в примере данные хорошо себя показали на не очень мощной машине с 2 GB RAM.

В каталоге /etc/nginx/conf.d/ создадим файл redmine.conf со следующим содержимым:

upstream redmine {
        server unix:/var/run/redmine/redmine.0.sock;
}

server {
    listen 80;
    server_name sharkon.ru;
    access_log off;
    error_log /var/log/redmine/nginx_error.log;
    include /etc/nginx/proxy_params.conf;
    proxy_redirect off;

    location / {
        root /var/www/sharkon.ru;
    }
    
    location /redmine {
        root /usr/share/redmine/public;
        error_page 404 404.html;
        error_page 500 502 503 504 500.html;
        try_files $uri/index.html $uri.html $uri @redmine_server;
    }

    location @redmine_server {
        proxy_pass http://redmine;
    }
}

Здесь указано, что следует использовать для соединения с Redmine сокет, расположенный по пути /var/run/redmine/. Имя сокета формируется из строки, указанной ранее в параметрах thin плюс порядковый номер созданного сокета, начиная с нуля. Далее идёт указание имени нашего сервера и пути, по которому расположен Redmine. Все запросы к нему автоматически будут переадресовываться к созданному ранее сокету.

Миграции

Т.к. мы настраивали доступ к БД вручную, создание её структуры мы будем производить вручную. Это не сложно:

cd /usr/share/redmine
rake db:migrate RAILS_ENV=production

Права на сокет

Так как сокет для redmine будет создаваться пользователем www-data, следует сделать так, чтобы после перезагрузки системы Redmine мог создать его заново. Для этого мы сменим владельца папки с сокетами и pid-файлом.

cd /var/run
mkdir redmine
chown www-data:www-data redmine/

Кодировка CSV-файлов

По-умолчанию Redmine генерирует все отчёты в кодировке UTF-8. Пакет Microsoft Office использует кодировку Win1251, поэтому CVS-отчёт, открытый с помощью Excel, будет показывать кракозябры. Следует всего лишь в одном месте изменить настройки:

cd /usr/share/redmine/config/locale
nano ru.yml

Здесь следует найти строку:

general_csv_encoding: UTF-8

и заменить её на

general_csv_encoding: CP1251

При необходимости здесь же можно изменить и другие параметры локализации Redmine, например, перевод некоторых слов и кодировку файлов pdf.

Запуск

Все подготовительные операции выполнены, можно запустить сам Redmine и перезапустить nginx.

service thin start
service nginx restart

Redmine будет доступен по адресу http://sharkon.ru/redmine/

Nginx + PHP-FPM в Debian 7

Введение

В статье рассматривается настройка сервера Debian 7 для размещения проектов PHP в связке с Nginx и PHP-FPM.

Долгое время мне вполне хватало возможностей Apache для разработки моих проектов на PHP. Были некоторые трудности с .htaccess и перенаправлением всех запросов на Front Controller, однако, чуть позже я понял, что Apache уже не может полностью удовлетворить моей тяги к максимальной производительности и начал искать другие пути. Почитав, я выяснил, что доля интернет-серверов под управлением Apache неуклонно снижается на протяжении уже нескольких лет, на замену ему приходят другие, которые дают бОльшую произодительность с меньшей затратой машинных ресурсов. Среди множества решений я выбрал PHP-FPM. Судя по тестам производительности, произведённым многими энтузиастами, именно он в связке с Nginx является наиболее перспективным способом размещения сайтов на PHP.

Цели

  • Увязка PHP-FPM с nginx
  • Конфигурирование параметров сайта для его корректной работы через Front Controller

Установка необходимого ПО

Добавим в список репозитории nginx, предварительно создав файл nginx.list в каталоге /etc/apt/sources.list.d/:

cd /etc/apt/sources.list.d/
touch nginx.list
/etc/apt/sources.list.d/nginx.list
deb http://nginx.org/packages/debian/ wheezy nginx
deb-src http://nginx.org/packages/debian/ wheezy nginx

Скачиваем ключ репозитория:

wget http://nginx.org/keys/nginx_signing.key

Установка ключей в deb-системах делается так:

apt-key add nginx_signing.key

Теперь можно выполнить установку всех необходимых программ:

apt-get update && apt-get install php5 php5-fpm nginx -y
Кратко по списку:
  • php5 и php5-fpm - интерпретатор и FastCGI-сервер для него
  • nginx - проксирующий сервер, будет нашим Front-End, т.е. сервером, принимающим запросы пользователя. Не путать с Front Controller, это совершенно разные вещи!

Настройка PHP и PHP-FPM

При установке PHP-FPM создаёт внутри каталога /etc/php5 подкаталог fpm. Внутри этого каталога находится несколько нужных нам файлов и подкаталогов. Первым делом вносим изменения в файл /etc/php5/fpm/php.ini

cd /etc/php5/fpm
nano php.ini

Здесь множество настроек, которые влияют на поведение PHP. В качестве символа комментария следует использовать точку с запятой. Самыми полезными я считаю следующие настройки:

  • short_open_tag = Off - использование коротких тегов считать ошибкой. Официальная документация по PHP рекомендует не использовать короткие теги.
  • asp_tags = Off - мы тут всё-таки на PHP пишем, а не на ASP.NET
  • max_execution_time = 60 - для некоторых CMS, например, Drupal, стандартных 30 секунд часто не хватает для выполнения некоторых скриптов, например, обновления
  • error_reporting = E_ALL - разработчику нужно видеть все ошибки. Если сервер боевой, нужно выставить в значение E_ALL & ~E_DEPRECATED & ~E_STRICT
  • display_errors = On - для разработки, для боевых условий - Off
  • display_startup_errors = On - аналогично
  • post_max_size = 16M - можно и больше, если через POST будут передаваться достаточно большие объёмы данных
  • default_charset = "UTF-8" - обязательно, если хочется избавиться от большинства проблем с кодировкой. Осторожно! Настройка влияет на весь сервер. Также кодировку можно задать в самом скрипте!
  • cgi.fix_pathinfo=1 - пригодится, если приложение работает через Front Controller
  • upload_max_filesize = 32M - можно и больше, если на сервер будут загружаться большие файлы
  • default_socket_timeout = 60 - в нашем случае связь с Nginx будет именно через сокет. Не стоит выставлять слишком большие значения, это приведёт к падению производительности.

Остальные настройки в этом файле можете делать по своему усмотрению.

Теперь нужно подредактировать файл www.conf в каталоге pool.d/www.conf

nano pool.d/www.conf

Следует изменить user и group на те, от имени которых будут выполняться скрипты. Не следует выполнять их от имени root, это дыра в безопасности. Я рекомендую указывать здесь владельца каталога /var/www

user = www-data
group = www-data

Не менее важная настройка:

listen = /var/run/php5-fpm.sock

Именно через этот сокет будет производиться обмен данными с Nginx. Остальные настройки я рекомендую оставить по умолчанию. Их тонкая настройка заслуживает отдельной подробной статьи.

После сохранения изменений следует перезапустить php-fpm:

service php5-fpm restart

Настройка Nginx

Перейдём в каталог настроек nginx:

cd /etc/nginx/

Здесь нам нужны 2 файла:

  • nginx.conf - основной файл конфигурации сервера
  • fastcgi_params - настройки Nginx для работы с FastCGI-серверами, например, PHP-FPM

Я привёл содержимое этих файлов к следующему виду:

nginx.conf
user nginx;
worker_processes 2;         # По числу ядер/процессоров, либо эмпирическим путём
worker_priority  -5;        # Отрицательные числа задают более высокий приоритет
worker_rlimit_nofile 2048;  # Можно открыть сразу 2048 подключений без изменения параметров ядра

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;

    keepalive_timeout  60; #Поддерживать подключение 1 минуту

    client_max_body_size 20m; #Разрешить загрузку файлов до 20 МБ
    server_tokens off;

    #Сжатие передаваемых данных
    gzip  on;
    gzip_disable "msie6";
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_types text/plain text/css application/x-javascript text/xml application/xml+rss text/javascript;

    include /etc/nginx/conf.d/*.conf;
}
В конец файла fastcgi_params нужно добавить всего одну строчку, вот эту:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

Теперь в каталоге /etc/nginx/conf.d/ создадим файл site.conf

nano /etc/nginx/conf.d/site.conf
index index.php;
server {
    server_name www.site.ru;
    rewrite ^ $scheme://site.ru$request_uri? permanent;
}
server {
    server_name site.ru;
    access_log /var/www/site.ru/log/access.log;
    error_log /var/www/site.ru/log/error.log;
    root /var/www/site.ru;

    location / {
        try_files $uri $uri/ /index.php?$request_uri;
        index index.php;
    }

    location ^~ /protected/ {
        deny all;
    }

    location ~ \.php$ {
        try_files $uri = 404;
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }
}

Разберём по частям этот файл:

index index.php;

Считать страницей по-умолчанию index.php

server {
    server_name www.site.ru;
    rewrite ^ $scheme://site.ru$request_uri? permanent;
}

Все запросы на http://www.site.ru автоматически переадресовывать к http://site.ru/

server_name site.ru;
access_log /var/www/site.ru/log/access.log;
error_log /var/www/site.ru/log/error.log;
root /var/www/site.ru;

Собственно наш сервер, с указанием его имени, логов и указанием корневого каталога

location / {
    try_files $uri $uri/ /index.php?$request_uri;
    index index.php;
}

Тут указано, что все запросы вида http://site.ru/login/auth следует переадресовывать к http://site.ru/index.php - как раз то, что нужно для Front Controller'а

location ^~ /protected/ {
    deny all;
}

Запрещаем любые обращения к папке protected нашего сайта. Там лежат исходные коды, к которым будет обращаться только index.php, веб-сервер их отдавать не должен.

location ~ \.php$ {
    try_files $uri = 404;
    include fastcgi_params;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

Выдавать ошибку 404, если запрошенный php-файл не найден. В остальном - просто переадресовать запрос на наш PHP-FPM-сервер. Также в этих строках выполняется подключение файла настроек /etc/nginx/fastcgi_params.

После выполнения всех операций следует перезапустить сервис Nginx

service nginx restart

Если исходные файлы сайта размещены в каталоге /var/www/site.ru/, а также этот каталог содержит подкаталог log, владельцем которого является www-data, то при обращении к сайту мы увидим главную страницу.