{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "M9K blog: заметки с тегом Debian 13",
    "_rss_description": "Заметки обо всём: devops, lifestyle, культура.",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/blog.m9k.space\/tags\/debian-13\/",
    "feed_url": "https:\/\/blog.m9k.space\/tags\/debian-13\/json\/",
    "icon": "https:\/\/blog.m9k.space\/pictures\/userpic\/userpic@2x.jpg?1769095194",
    "authors": [
        {
            "name": "M",
            "url": "https:\/\/blog.m9k.space\/",
            "avatar": "https:\/\/blog.m9k.space\/pictures\/userpic\/userpic@2x.jpg?1769095194"
        }
    ],
    "items": [
        {
            "id": "248",
            "url": "https:\/\/blog.m9k.space\/all\/egeya-hroniki-obnovleniya\/",
            "title": "Эгея. Хроники обновления.",
            "content_html": "<p>Когда-то, в далёкие времена ковида и окончательного огосударствления ВК, посетила меня идея поднять свой бложик на Aegea. Поднимал его я на актуальном тогда Proxmox 5, ещё ого-го как живом CentOS 7 в LXC. Внутри была, страшно сказать, MariaDB 5 и несвежий апачик. Утекло с тех лет много воды: контейнер несколько раз менял хостовый Proxmox, но внутрянку я не трогал.<\/p>\n<p>И тут зачесались руки привести историческую инфраструктуру в CI-ный вид: плейбук там, плейбук тут.<\/p>\n<p>База — Debian 13, обновление с миграцией на свежую версию движка, потому что с 2020 года Aegea я обновлял всего один раз.<\/p>\n<p>Вообще, это заметка должна была быть одой LLM и <s>нытьём<\/s> на тему того, что нейросети заменят админодевопсов нафиг.<\/p>\n<p>И, в общем и целом, я был в восторге. Написав некоторую длинную портянку текста о том, что, как и почему, я получил длинный плейбук, который, без шуток, выполнился с первого захода. И это с учётом того, что исходный сервер настраивал админ с сильно меньшим пониманием жизни и профессии.<\/p>\n<p>Отрефлексировать я это отрефлексировал тем, что ТЗ было составлено с кучей ограничений, которые человек без опыта ковыряния во всём этом просто не сформулировал бы. Машине скормили хороший запрос — машина выдала хороший результат. Плейбук был запущен, и через пару минут я получил рабочий блог.<\/p>\n<p>Но рефлексия не удалась.<\/p>\n<p>При попытке загрузить картинку в новый пост ловлю: «не удалось зарегистрировать загруженный файл».<br \/>\nВ nginx access log:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">POST \/@ajax\/file-upload\/?entity=note&amp;entity-id=247 HTTP\/1.1&quot; 200<\/code><\/pre><p>При этом в \/var\/www\/blog\/pictures появлялись временные файлы:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">-rw------- 1 www-data www-data 0 upload-XXXXXX<\/code><\/pre><p>Очевидно: место, права, лимиты на аплоад php, просто загрузку — проверил. PHP корректно получал файл:<br \/>\nДвижок в фришной версии обфусцирован, разбираться в коде — неблагодарное дело — мы холопоадмины, наше дело логи читать. Достаём BFG.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">strace -ff $(ps aux | awk &#039;\/php-fpm: pool www\/ &amp;&amp; !\/awk\/ {printf &quot;-p %s &quot;, $2}&#039;) -o \/tmp\/egeya-upload.strace<\/code><\/pre><p>Проблема раз:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">rename(&quot;\/tmp\/phpXXXX&quot;, &quot;\/var\/www\/blog\/pictures\/upload-XXXX&quot;) = -1 EXDEV<\/code><\/pre><p>Ошибка:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">EXDEV (Invalid cross-device link)<\/code><\/pre><p>означает попытку `rename()` между разными файловыми системами.<\/p>\n<p>Смотрю на вывод df -T в исходной системе, и в target — и понимаю, что Debian (не)смог. \/tmp теперь не реальный каталог, а временная фс в памяти tmpsfs<\/p>\n<p>Схема проблемы:<br \/>\n\/tmp<br \/>\n|<br \/>\n| tmpfs<br \/>\n|<br \/>\nX  rename()<br \/>\n|<br \/>\n\/var\/www\/blog\/pictures<br \/>\n|<br \/>\n| root filesystem<\/p>\n<p>PHP создавал временный upload-файл в \/tmp.<br \/>\nЭгея использовала move_uploaded_file(), который внутри PHP может выполнить быстрый rename().<br \/>\nНо rename(), как оказалось, между разными файловыми системами невозможен.<br \/>\nБахнул отдельный временный каталог на той же файловой системе, где и бложик.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">mkdir -p \/var\/www\/blog\/tmp\nchown www-data:www-data \/var\/www\/blog\/tmp\nchmod 700 \/var\/www\/blog\/tmp<\/code><\/pre><p>В PHP-FPM :<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">upload_tmp_dir = \/var\/www\/blog\/tmp<\/code><\/pre><p>После перезапуска:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">systemctl restart php8.2-fpm<\/code><\/pre><p>цепочка стала:<br \/>\n\/var\/www\/blog\/tmp\/phpXXXX<br \/>\n|<br \/>\n| rename()<br \/>\nv<br \/>\n\/var\/www\/blog\/pictures\/upload-XXXX<br \/>\nОшибка EXDEV исчезла — но аплоад не заработал.<br \/>\nДостаём BFG второй раз.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">strace -ff $(ps aux | awk &#039;\/php-fpm: pool www\/ &amp;&amp; !\/awk\/ {printf &quot;-p %s &quot;, $2}&#039;) -o \/tmp\/egeya-upload.strace<\/code><\/pre><p>Видим, что Эгея хочет поделиться тайнами мироздания в лог, но не может.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">touch \/var\/www\/blog\/user\/logs\/main.log<\/code><\/pre><p>Повторяем аплоад:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">Process image: Done\nRegister upload: &lt;, , add, Array&gt;\nAjax file upload: couldn’t register upload<\/code><\/pre><p>Явно не фешный, не хватает параметров. Смотрим консоль отладки. Должны быть entity и entity-id<br \/>\nСмотрим в nginx. Конфиг нагенерила LLM по мотивам того, что было в сети — и он был рабочий...формально.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">location \/ {\n    log_not_found off;\n    try_files $uri $uri\/ \/index.php?go=$uri;\n}<\/code><\/pre><p>Запрос \/@ajax\/file-upload\/?entity=note&entity-id=247 после try_files превращался в \/index.php?go=\/@ajax\/file-upload\/. Параметры говорили «Мұнда параметрлер жоқ қой, иттер»<br \/>\nМеняем чудо-LLM на рабочее:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">location \/ {\n    log_not_found off;\n    rewrite ^(.*)$ \/index.php?go=$1 last;\n}<\/code><\/pre><p>Смысл изменения:<br \/>\ntry_files при внутреннем перенаправлении формирует новый URI и может потерять исходную строку параметров.<br \/>\nrewrite ... last выполняет внутренний rewrite с сохранением исходных GET-параметров. Рестартуем Nginx.<\/p>\n<p>Бинго!<\/p>\n",
            "summary": "Когда-то, в далёкие времена ковида и окончательного огосударствления ВК, посетила меня идея поднять свой бложик на Aegea",
            "date_published": "2026-09-25T23:22:24+07:00",
            "date_modified": "2026-09-25T23:33:07+07:00",
            "tags": [
                "Aegea",
                "Debian 13",
                "системное администрирование",
                "Эгея"
            ],
            "_date_published_rfc2822": "Fri, 25 Sep 2026 23:22:24 +0700",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "248",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        }
    ],
    "_e2_version": 4199,
    "_e2_ua_string": "Aegea 11.5 (v4199)"
}