Заметки ITшника обо всём

Эгея. Хроники обновления.

Когда-то, в далёкие времена ковида и окончательного огосударствления ВК, посетила меня идея поднять свой бложик на Aegea. Поднимал его я на актуальном тогда Proxmox 5, ещё ого-го как живом CentOS 7 в LXC. Внутри была, страшно сказать, MariaDB 5 и несвежий апачик. Утекло с тех лет много воды: контейнер несколько раз менял хостовый Proxmox, но внутрянку я не трогал.

И тут зачесались руки привести историческую инфраструктуру в CI-ный вид: плейбук там, плейбук тут.

База — Debian 13, обновление с миграцией на свежую версию движка, потому что с 2020 года Aegea я обновлял всего один раз.

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

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

Отрефлексировать я это отрефлексировал тем, что ТЗ было составлено с кучей ограничений, которые человек без опыта ковыряния во всём этом просто не сформулировал бы. Машине скормили хороший запрос — машина выдала хороший результат. Плейбук был запущен, и через пару минут я получил рабочий блог.

Но рефлексия не удалась.

При попытке загрузить картинку в новый пост ловлю: «не удалось зарегистрировать загруженный файл».
В nginx access log:

POST /@ajax/file-upload/?entity=note&entity-id=247 HTTP/1.1" 200

При этом в /var/www/blog/pictures появлялись временные файлы:

-rw------- 1 www-data www-data 0 upload-XXXXXX

Очевидно: место, права, лимиты на аплоад php, просто загрузку — проверил. PHP корректно получал файл:
Движок в фришной версии обфусцирован, разбираться в коде — неблагодарное дело — мы холопоадмины, наше дело логи читать. Достаём BFG.

strace -ff $(ps aux | awk '/php-fpm: pool www/ && !/awk/ {printf "-p %s ", $2}') -o /tmp/egeya-upload.strace

Проблема раз:

rename("/tmp/phpXXXX", "/var/www/blog/pictures/upload-XXXX") = -1 EXDEV

Ошибка:

EXDEV (Invalid cross-device link)

означает попытку `rename()` между разными файловыми системами.

Смотрю на вывод df -T в исходной системе, и в target — и понимаю, что Debian (не)смог. /tmp теперь не реальный каталог, а временная фс в памяти tmpsfs

Схема проблемы:
/tmp
|
| tmpfs
|
X rename()
|
/var/www/blog/pictures
|
| root filesystem

PHP создавал временный upload-файл в /tmp.
Эгея использовала move_uploaded_file(), который внутри PHP может выполнить быстрый rename().
Но rename(), как оказалось, между разными файловыми системами невозможен.
Бахнул отдельный временный каталог на той же файловой системе, где и бложик.

mkdir -p /var/www/blog/tmp
chown www-data:www-data /var/www/blog/tmp
chmod 700 /var/www/blog/tmp

В PHP-FPM :

upload_tmp_dir = /var/www/blog/tmp

После перезапуска:

systemctl restart php8.2-fpm

цепочка стала:
/var/www/blog/tmp/phpXXXX
|
| rename()
v
/var/www/blog/pictures/upload-XXXX
Ошибка EXDEV исчезла — но аплоад не заработал.
Достаём BFG второй раз.

strace -ff $(ps aux | awk '/php-fpm: pool www/ && !/awk/ {printf "-p %s ", $2}') -o /tmp/egeya-upload.strace

Видим, что Эгея хочет поделиться тайнами мироздания в лог, но не может.

touch /var/www/blog/user/logs/main.log

Повторяем аплоад:

Process image: Done
Register upload: <, , add, Array>
Ajax file upload: couldn’t register upload

Явно не фешный, не хватает параметров. Смотрим консоль отладки. Должны быть entity и entity-id
Смотрим в nginx. Конфиг нагенерила LLM по мотивам того, что было в сети — и он был рабочий...формально.

location / {
    log_not_found off;
    try_files $uri $uri/ /index.php?go=$uri;
}

Запрос /@ajax/file-upload/?entity=note&entity-id=247 после try_files превращался в /index.php?go=/@ajax/file-upload/. Параметры говорили «Мұнда параметрлер жоқ қой, иттер»
Меняем чудо-LLM на рабочее:

location / {
    log_not_found off;
    rewrite ^(.*)$ /index.php?go=$1 last;
}

Смысл изменения:
try_files при внутреннем перенаправлении формирует новый URI и может потерять исходную строку параметров.
rewrite ... last выполняет внутренний rewrite с сохранением исходных GET-параметров. Рестартуем Nginx.

Бинго!

Отправить
Поделиться
Твитнуть