Bash Ready | Linux
4.07K subscribers
513 photos
20 videos
482 links
По всем вопросам: @AdilNow
Download Telegram
🐳 Основы Docker — упаковываем приложения в контейнеры

Если фраза «на моем компьютере всё работает» стала для вас проклятием при деплое, пора переходить на Docker. Это технология контейнеризации, которая позволяет упаковать приложение со всеми его зависимостями, библиотеками и конфигами в один изолированный образ, который запустится везде одинаково.

В отличие от виртуальных машин, контейнеры не копируют целую операционную систему. Они используют ядро основной системы (Host OS), что делает их невероятно легкими и быстрыми. Запуск контейнера занимает секунды, а не минуты.

Основные понятия:
Dockerfile — текстовый файл-рецепт, по которому собирается образ.
Image (Образ) — «замороженный» снимок вашего приложения (аналог инсталлятора).
Container (Контейнер) — запущенный и работающий экземпляр образа.

Базовые команды для работы:
Запустить контейнер: docker run -d -p 8080:80 nginx (флаг -d запускает в фоне, а -p пробрасывает порты).
Посмотреть запущенные: docker ps
Остановить контейнер: docker stop [ID_контейнера]
Посмотреть логи внутри контейнера: docker logs -f [ID_контейнера]

Зачем это инженеру? Для чистоты и порядка. Вам больше не нужно захламлять основную систему разными версиями Python, Node.js или базами данных. Вы можете запустить PostgreSQL одной командой, поработать с ней и удалить контейнер, не оставив в системе ни одного лишнего файла.

Контейнеры обеспечивают идеальную изоляцию. Если ваше приложение внутри Docker «упадет» или попытается занять всю память, это не затронет остальные процессы на сервере (если настроены лимиты). Это стандарт для современного бэкенда, микросервисов и CI/CD процессов.

Чтобы не вводить длинные команды в терминале, для управления группой контейнеров (например, приложение + база данных + кэш) используют Docker Compose. Но это уже тема для отдельного большого разговора.

Использование Docker превращает процесс развертывания софта из сложного квеста в простую и предсказуемую задачу. Это один из важнейших навыков для любого IT-специалиста в 2026 году.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
🛠️ Docker Compose — управляем оркестром контейнеров

Если Docker — это один контейнер, то Docker Compose — это дирижер, который запускает целую связку сервисов одной командой. Вам больше не нужно по очереди поднимать базу данных, бэкенд и Redis, прописывая каждому порты и сети вручную. Все настройки хранятся в одном файле docker-compose.yml.

Вместо длинных цепочек в терминале вы описываете архитектуру проекта в формате YAML. Это позволяет версиировать инфраструктуру так же, как и обычный код.

Пример простого конфига:

version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret_password



Основные команды:
Запустить всё разом: docker-compose up -d (флаг -d запустит всё в фоновом режиме).
Остановить и удалить всё: docker-compose down (очищает контейнеры и сети, созданные проектом).
Посмотреть статус: docker-compose ps
Пересобрать образы после правок кода: docker-compose up --build

Зачем это инженеру? Для быстрого развертывания среды разработки. Новый коллега может скачать проект из Git, выполнить docker-compose up, и через минуту у него будет полностью рабочее окружение со всеми базами данных и зависимостями, настроенными ровно так же, как у вас.

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

Использование Docker Compose избавляет от ошибок ручного ввода и гарантирует, что проект запустится в идентичном виде на вашем ноутбуке, на сервере для тестов и на продакшене. Это следующий уровень профессиональной работы с контейнерами.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🐍 Python-скрипты в фоне — управляем через Systemd!

Вы написали крутого Telegram-бота или парсер на Python, запустили его в терминале, но стоит закрыть консоль или разорвать SSH-соединение — и процесс умирает. Чтобы скрипт работал вечно, сам перезапускался после сбоев и поднимался после перезагрузки сервера, его нужно превратить в системную службу (service) через Systemd.

---

Systemd — это стандартный менеджер систем и служб в Linux. Вместо того чтобы городить костыли с nohup или &, вы создаете один простой конфиг-файл, который берет на себя весь контроль над вашим кодом.

Как это настроить:

Создайте файл службы: sudo nano /etc/systemd/system/my_bot.service

Наполните его конфигурацией:

[Unit]
Description=My Python Telegram Bot
After=network.target

[Service]
User=user
WorkingDirectory=/home/user/my_project
ExecStart=/home/user/my_project/venv/bin/python main.py
Restart=always

[Install]
WantedBy=multi-user.target



В блоке ExecStart важно указывать полный путь к интерпретатору Python (лучше из виртуального окружения venv), а параметр Restart=always гарантирует, что если ваш скрипт «упадет» с ошибкой, система сама поднимет его через пару секунд.

Основные команды для управления:
Обновить список служб: sudo systemctl daemon-reload
Запустить бота: sudo systemctl start my_bot
Включить автозагрузку при старте сервера: sudo systemctl enable my_bot
Проверить статус: sudo systemctl status my_bot

Зачем это инженеру? Это превращает ваш «скрипт на коленке» в надежное серверное решение. Вам больше не нужно проверять вручную, работает ли бот. Вы можете смотреть логи службы через уже знакомый нам journalctl -u my_bot и точно знать, когда и почему произошла ошибка.


🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🌐 Обратный прокси — зачем нужен Nginx перед вашим кодом?

Когда вы запускаете Python-бота, FastAPI-приложение или Node.js сервер, они обычно работают на портах вроде 8000 или 5000. Выставлять их напрямую в интернет — плохая идея. Профессиональный стандарт — ставить «перед» ними Nginx в режиме Reverse Proxy (обратного прокси).



Nginx — это сверхбыстрый веб-сервер, который принимает все входящие запросы из интернета на стандартные порты (80 и 443) и аккуратно перенаправляет их вашему приложению, работающему глубоко внутри системы.

Что это дает на практике:
SSL-сертификаты: Nginx берет на себя шифрование (HTTPS). Вашему коду не нужно знать, как работать с сертификатами — он просто получает чистый трафик.
Безопасность: Вы закрываете все порты файрволом, кроме 80 и 443. Приложение становится невидимым для прямых атак.
Статика: Картинки, видео и CSS-файлы Nginx отдает в разы быстрее, чем Python или JS, разгружая ваш основной код.
Отказоустойчивость: Если у вас запущено несколько копий приложения, Nginx может распределять нагрузку между ними (Load Balancing).

Минимальный конфиг для проксирования:
Создается файл в /etc/nginx/sites-available/my_app:

server {
listen 80;
server_name your_domain.com;

location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}



Зачем это инженеру? Это финальный штрих, который превращает «скрипт, запущенный в консоли» в полноценный веб-сервис. Без Nginx вы не сможете подключить нормальный домен с HTTPS (через Certbot) и защитить приложение от элементарных DDoS-атак или переполнения соединений.

Использование обратного прокси позволяет вам гибко обновлять приложение: вы можете остановить сервис, а Nginx в это время будет показывать пользователям красивую страницу «Технические работы» вместо ошибки «Соединение сброшено». Это стандарт, без которого не обходится ни один серьезный проект в вебе.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🔒 Безопасность в один клик — ставим SSL через Certbot

Если вы настроили Nginx, ваш сайт уже доступен, но браузеры помечают его как «Незащищенный». В 2026 году HTTPS — это не роскошь, а обязательное требование. Чтобы бесплатно получить SSL-сертификат от Let's Encrypt и настроить его автоматическое обновление, используется утилита Certbot.

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

Как превратить http в https за пару минут:

Установка Certbot и плагина для Nginx:
sudo apt update && sudo apt install certbot python3-certbot-nginx

Запуск магии:
sudo admin certbot --nginx -d your_domain.com (можно указать несколько доменов через -d).

Во время работы Certbot спросит ваш email (для уведомлений об истечении срока) и предложит автоматически настроить редирект с HTTP на HTTPS. Всегда выбирайте «Redirect» — это гарантирует, что пользователи всегда будут на защищенной версии сайта.

Зачем это инженеру? Во-первых, это доверие пользователей и поисковиков. Во-вторых, это защита данных: без HTTPS любой посредник в сети (например, провайдер в кафе) может перехватить пароли или токены, которые передаются между браузером и вашим сервером.

Сертификаты Let's Encrypt выдаются на 90 дней, но Certbot автоматически добавляет задачу в планировщик. Проверить, сработает ли автопродление в будущем, можно командой:
sudo certbot renew --dry-run

Использование Certbot делает процесс управления безопасностью невидимым и надежным. Вам больше не нужно следить за датами и вручную копировать ключи — система всё сделает за вас, поддерживая «зеленый замочек» в адресной строке вечно.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📊 Индексы в базах данных — как ускорить запросы в 100 раз?

Представьте, что вы ищете главу в бумажной книге на 500 страниц. Если листать по порядку, вы потратите уйму времени. Но если заглянуть в оглавление в конце книги, вы найдете нужную страницу за секунды. Индексы в базах данных (PostgreSQL, MySQL, SQLite) работают точно так же.

По умолчанию база данных выполняет Full Table Scan — она перебирает каждую строчку в таблице, чтобы найти нужную. Если у вас 100 записей, это мгновенно. Если 10 миллионов — сервер «задохнется». Индекс создает отдельную структуру (обычно это B-Tree или B-дерево), где данные отсортированы, что позволяет базе находить значения с помощью бинарного поиска.

Когда стоит создавать индекс:
— В колонках, по которым вы часто делаете WHERE (например, email, user_id).
— В полях, используемых для сортировки (ORDER BY).
— В полях, по которым происходит объединение таблиц (JOIN).

Как создать индекс (на примере SQL):

CREATE INDEX idx_user_email ON users(email);



Зачем это инженеру? Это самый дешевый и эффективный способ оптимизации бэкенда. Часто разработчики пытаются купить сервер помощнее или переписать код на Python, хотя проблема решается добавлением одного индекса. Запрос, который длился 5 секунд, после индексации может выполняться за 0.05 секунды.

Однако у индексов есть «цена». Каждый новый индекс замедляет операции записи (INSERT, UPDATE, DELETE), так как базе нужно обновлять не только таблицу, но и само «оглавление». Также индексы занимают место на диске. Поэтому золотое правило: индексируйте только те поля, по которым реально идет поиск.

Чтобы проверить, использует ли база ваш индекс, используйте команду EXPLAIN ANALYZE перед вашим запросом. Она покажет «план выполнения» и честно ответит, просмотрела ли база всю таблицу или воспользовалась быстрым индексом.

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

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
5
🐳 Кастомные Docker-образы — пишем правильный Dockerfile

Запуск готовых контейнеров вроде Nginx или PostgreSQL — это здорово, но для деплоя собственного приложения (на Python, Node.js или Go) нужно научиться собирать свои образы. Для этого пишется Dockerfile — текстовый файл с пошаговыми инструкциями для сборки.

Каждая строчка в Dockerfile создает новый слой образа. Чем меньше весят эти слои и чем лучше они кэшируются, тем быстрее будет собираться и разворачиваться ваш проект.

Пример правильного Dockerfile для Python (FastAPI):

# 1. Базовый образ (минималистичный alpine или slim)
FROM python:3.11-slim

# 2. Установка рабочей директории
WORKDIR /app

# 3. Копируем файлы зависимостей отдельно (для кэширования слоев)
COPY requirements.txt .

# 4. Установка пакетов без сохранения кэша менеджера
RUN pip install --no-cache-dir -r requirements.txt

# 5. Копируем остальной код приложения
COPY . .

# 6. Указываем порт, который слушает приложение
EXPOSE 8000

# 7. Команда для запуска
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]



Зачем это инженеру? Для создания стандартизированной среды. Копирование requirements.txt перед основным кодом — это классический паттерн. Если вы измените строчку в коде, но не тронете зависимости, Docker при сборке возьмет готовый слой с установленными библиотеками из кэша за долю секунды, а не будет скачивать их заново.

Также важно следить за безопасностью и размером. Использование легковесных образов (с тегом -slim или -alpine) уменьшает размер итогового контейнера с условного гигабайта до 100–150 мегабайт. Маленький образ быстрее передается по сети на сервер и содержит меньше потенциальных уязвимостей в системных библиотеках.

Для еще большей оптимизации используют Multi-stage builds (многоэтапную сборку), когда в одном Dockerfile первый контейнер собирает проект (используя тяжелые инструменты компиляции), а второй — просто забирает готовый результат, оставаясь максимально чистым.

Написание кастомных Dockerfile переводит работу с инфраструктурой на уровень "Infrastructure as Code" (Инфраструктура как код). Теперь процесс сборки вашего приложения задокументирован, автоматизирован и не зависит от настроек конкретного сервера.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🔄 Миграции баз данных — как менять структуру без потери данных?

В начале проекта ваша база данных выглядит просто: таблица users с полями id и username. Но проект растет, и вам нужно добавить поле email, изменить тип данных у пароля или создать связь с новой таблицей заказов. Делать это вручную через SQL-запросы на живом сервере — верный путь уронить продакшен и потерять данные. Для правильного управления схемой используют миграции.

Миграции — это система контроля версий для вашей базы данных. Каждое изменение структуры оформляется в виде небольшого файла-скрипта (на Python, JS или чистом SQL), который содержит две обязательные инструкции:
Upgrade (Up): что конкретно нужно сделать (например, добавить колонку).
Downgrade (Down): как откатить это изменение назад, если что-то пошло не так.

В экосистеме Python стандартом для миграций являются Alembic (для SQLAlchemy) или встроенный механизм в Django ORM.

Как выглядит типичный процесс работы:
— Вы меняете модель в коде приложения.
— Генерируете файл миграции: alembic revision --autogenerate -m "add_email_to_user".
— Инструмент сравнивает ваш код с текущей базой и создает файл, где прописаны команды вроде op.add_column(...).
— Применяете изменения: alembic upgrade head.

Зачем это инженеру? Для командной разработки и безопасного деплоя. Когда ваш коллега скачает свежий код из Git, ему не придется гадать, какие таблицы вы добавили. Он просто запустит команду миграции, и его локальная база данных автоматически обновится до нужного состояния.

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

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

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

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🪵 Логирование без боли — почему стоит забыть про print()

Когда вы только учитесь кодировать, для проверки значений принято использовать обычный print(). Но в реальных проектах и на сервере print() становится бесполезным: он просто выплевывает текст в консоль, не говоря, когда произошла ошибка, в каком файле она случилась и насколько она критична. Для этого используют логирование (модуль logging или библиотеку Loguru).

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

Стандартные уровни логирования:
DEBUG: подробная информация для отладки (значения переменных, шаги цикла).
INFO: подтверждение, что всё идет по плану (сервер запущен, пользователь вошел).
WARNING: случилось что-то неожиданное, но программа работает (мало места на диске).
ERROR: серьезная проблема, часть функций не работает (ошибка базы данных).
CRITICAL: полная остановка системы (упал весь сервер).

В Python стандартный модуль logging требует настройки, поэтому в современном бэкенде часто используют Loguru. Она красивая, быстрая и настраивается в одну строчку.

Пример работы с Loguru:

from loguru import logger

# Настраиваем запись в файл с ротацией (чтобы файл не весил гигабайты)
logger.add("app.log", format="{time} {level} {message}", level="INFO", rotation="10 MB")

def divide(a, b):
try:
logger.debug(f"Делим {a} на {b}")
return a / b
except ZeroDivisionError:
logger.exception("Попытка деления на ноль!") # Автоматически запишет весь traceback ошибки

divide(10, 0)



Зачем это инженеру? Простой print() сотрется, как только закроется терминал. Правильный логгер сохраняет данные в файлы, автоматически снабжая каждую строчку точным временем, именем функции и уровнем важности.

Настроив ротацию (rotation="10 MB"), вы защищаете диск сервера: как только файл лога разрастется, Loguru заархивирует его и начнет новый. А благодаря правильным уровням вы сможете настроить отправку уведомлений в Telegram только для ошибок уровня ERROR и выше, не отвлекаясь на штатные INFO сообщения.

Переход от print() к логированию — это маркер взрослой разработки. Это дает возможность проводить аудит системы, понимать поведение пользователей и чинить баги за минуты, просто открыв лог-файл.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21😁1
🔒 Безопасное хранение паролей — зачем солить хэши?

Когда пользователь регистрируется на вашем сайте, он вводит пароль. Сохранять его в базу данных в чистом виде (plain text) — преступление против безопасности. Если злоумышленники взломают базу, они получат доступ к аккаунтам всех пользователей. Для защиты данных используют хэширование, но даже обычного хэша сегодня уже недостаточно.

---

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

Однако простые алгоритмы (MD5, SHA-1, SHA-256) работают слишком быстро. Хакеры используют радужные таблицы (Rainbow Tables) — гигантские базы заранее вычисленных хэшей для миллиардов популярных паролей. Если ваш пароль 123456, его хэш моментально найдется в такой таблице.

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

Как это работает:
— Пользователь вводит пароль: qwerty.
— Система генерирует случайную соль: x9F2kL.
— Пароль и соль соединяются, и хэшируется уже строка qwerty_x9F2kL.
— В базу данных сохраняются и соль, и полученный хэш.

Зачем это инженеру? Чтобы сделать радужные таблицы абсолютно бесполезными. Даже если два пользователя выберут одинаковый пароль 123456, из-за разной соли их хэши в базе данных будут кардинально отличаться. Хакеру придется подбирать пароль для каждого пользователя индивидуально методом брутфорса, на что уйдут годы.

В современном бэкенде (Python, Node.js, Go) для этого используют специальные «медленные» алгоритмы, такие как Bcrypt, Argon2 или Scrypt. Они намеренно заставляют процессор тратить миллисекунды на вычисление одного хэша. Для обычного пользователя задержка незаметна, но для хакера скорость перебора падает с миллионов вариантов в секунду до пары сотен.

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

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🧵 Потоки против Процессов — как заставить код работать параллельно?

Когда ваше приложение начинает делать несколько дел одновременно — например, обрабатывать запрос пользователя, скачивать картинку и считать тяжелую математику — вам нужно параллелить вычисления. В операционных системах и языках программирования (включая Python) для этого есть два главных инструмента: процессы (Processes) и потоки (Threads). Они звучат похоже, но работают совершенно по-разному.

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

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

В чем разница при написании кода:

Ресурсы: Создать процесс — «дорого» для процессора и оперативной памяти. Создать поток — в разы быстрее и легче.
Обмен данными: Потокам легко общаться друг с другом, ведь у них общая память. Процессам, чтобы передать данные друг другу, приходится использовать сложные механизмы (IPC, очереди, сокеты).
Безопасность: Если в одном из потоков случится критическая ошибка (например, Segmentation Fault), упадет весь процесс целиком со всеми остальными потоками. В случае с процессами — погибнет только один, изолированный элемент.

Зачем это инженеру? Чтобы правильно выбирать инструмент под конкретную задачу.

В Python есть своя специфика — GIL (Global Interpreter Lock). Это глобальная блокировка, которая разрешает только одному потоку выполнять код Python в один момент времени. Из-за этого потоки в Python идеально подходят для задач, связанных с ожиданием ввода-вывода (I/O-bound): например, делать запросы к API, скачивать файлы или ждать ответа от базы данных. Пока один поток ждет сеть, другой работает.

Если же вам нужно разгрузить процессор тяжелыми математическими расчетами, кодированием видео или обработкой больших данных (CPU-bound), потоки в Python не помогут — они будут выполняться по очереди на одном ядре. В этом случае нужно использовать процессы (multiprocessing), которые честно запустятся на разных ядрах вашего процессора.

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

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21😁1
🌐 Понимание REST API — как общаются современные сервисы?

Когда вы заказываете еду через приложение, проверяете прогноз погоды или авторизуетесь на сайте через Google, под капотом происходит одно и то же: разные программы общаются друг с другом. Самый популярный стандарт для такого общения — архитектурный стиль REST (Representational State Transfer).


В основе REST API лежит простая концепция: всё в системе является ресурсом (пользователь, заказ, статья, картинка). У каждого ресурса есть свой уникальный адрес (URL). Например, /api/v1/users — это адрес, по которому живут данные всех пользователей.

Чтобы совершить действие с ресурсом, клиент (браузер или мобилка) отправляет серверу стандартный HTTP-запрос, используя определенный метод (глагол).

Основные методы REST API:
GET — получить данные (например, открыть список постов). Этот метод безопасен: он не должен ничего менять в базе.
POST — создать новый ресурс (например, зарегистрировать пользователя или опубликовать новый пост).
PUT / PATCH — обновить существующие данные. PUT обычно заменяет ресурс целиком, а PATCH — меняет только отдельные поля.
DELETE — удалить ресурс.

Зачем это инженеру? REST делает систему гибкой и масштабируемой. Бэкенд, написанный на Python (FastAPI / Django), ничего не знает о том, как устроен фронтенд. Он просто принимает запросы и возвращает структурированный ответ — обычно в формате JSON.

Пример JSON-ответа от сервера:

{
"id": 42,
"username": "python_developer",
"status": "active"
}



Благодаря такому разделению вы можете полностью переписать мобильное приложение, но если структура REST API (эндпоинты и формат данных) осталась прежней, бэкенд даже не заметит изменений.

После обработки запроса сервер обязательно возвращает код ответа (HTTP Status Code), чтобы клиент сразу понял, что произошло:
2xx (например, 200 OK, 201 Created) — всё прошло успешно.
4xx (например, 400 Bad Request, 404 Not Found) — ошибка на стороне клиента (неверные данные, ресурс не существует).
5xx (например, 500 Internal Server Error) — ошибка на стороне сервера (код упал).

Проектирование чистых, понятных и предсказуемых REST API — один из главных навыков бэкенд-разработчика. Это позволяет легко интегрировать сервис с другими приложениями и делать архитектуру системы по-настоящему независимой.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🗄️ Хранилища Key-Value — зачем бэкенду нужен Redis?

В классических базах данных вроде PostgreSQL или MySQL данные лежат в таблицах на жестком диске. Это надежно, но медленно, если запрашивать их тысячи раз в секунду. Когда приложению нужна максимальная скорость, на сцену выходит Redis — высокопроизводительная СУБД типа «ключ-значение», которая хранит все данные прямо в оперативной памяти (In-Memory).
В Redis нет таблиц, строк и сложных SQL-запросов. Вся работа строится вокруг пар данных: вы записываете значение по определенному ключу, а затем мгновенно извлекаете его. Скорость чтения и записи в Redis измеряется микросекундами, что позволяет обрабатывать сотни тысяч запросов в секунду на скромном железе.

Два главных сценария использования Redis:

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

Зачем это инженеру? Redis избавляет основную базу от перегрузок. У Redis есть встроенный механизм TTL (Time To Live) — вы можете указать время жизни для любого ключа, например, 10 минут:

SET user_session_123 "active" EX 600



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

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

Главный минус Redis — оперативная память стоит дороже жестких дисков, а при внезапном отключении питания сервера данные, которые не успели сброситься на диск, могут стереться (хотя у Redis есть механизмы снапшотов RDB и логирования AOF). Поэтому Redis используют как дополнение к основной базе, переводя скорость работы приложения на космический уровень.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥1
🐳 Очистка Docker — как вернуть гигабайты дискового пространства

Docker — потрясающий инструмент, но у него есть вредная привычка: он незаметно пожирает место на жестком диске. Вы обновили код, пересобрали образ, запустили новый контейнер — а старые слои, неиспользуемые тома и остановленные контейнеры остались лежать мертвым грузом. Со временем эта «свалка» может забить диск сервера на 100%, что приведет к падению всех приложений.

Когда вы пересобираете образ, старые слои теряют связь с тегами и превращаются в так называемые dangling (зависшие) образы. В выводе команды docker images они отображаются со странными именами <none>:<none>. Сами по себе они уже никогда не очистятся.

Главная команда для генеральной уборки:

docker system prune



Эта команда в один клик удаляет:
— Все остановленные контейнеры.
— Все неиспользуемые сети (networks).
— Все «зависшие» (<none>:<none>) образы и кэш сборки.

Если вы хотите пойти дальше и снести вообще все неиспользуемые образы (даже те, у которых есть нормальные теги, но которые сейчас просто не запущены), добавьте флаг -a:

docker system prune -a



Зачем это инженеру? Для предотвращения критических сбоев. Но здесь кроется важный нюанс: по умолчанию docker system prune не трогает тома (Volumes). И это сделано ради вашей безопасности, ведь в томах хранятся боевые данные — например, файлы вашей базы данных PostgreSQL или Redis.

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

docker system prune --volumes



Или точечно через команду docker volume prune.

Чтобы держать сервер в тонусе и не доводить диск до критической отметки, опытные админы не чистят всё руками. Они один раз настраивают уже знакомый нам планировщик Cron, добавляя туда задачу выполнять автоматическую базовую очистку docker system prune -f (флаг -f убирает подтверждение y/n) раз в неделю.

Регулярный мониторинг свободного места с помощью команды df -h и своевременный запуск очистки Docker — это простое правило гигиены, которое убережет ваши серверы от внезапных остановок и сэкономит кучу нервов.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
⚙️ Переменные окружения — как правильно хранить секреты проекта

Никогда не пишите пароли от баз данных, токены Telegram-ботов и секретные ключи API прямо в коде (хардкод). Если вы случайно выложите такой проект в публичный репозиторий на GitHub, злоумышленники найдут ключи за пару минут с помощью автоматических парсеров. Для безопасного управления конфигурацией используют переменные окружения (Environment Variables или env).

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

В процессе разработки стандартным решением является использование файла **.env, который создается в корне проекта.

Пример структуры файла .env:**

DATABASE_URL=postgresql://user:secret_pass@localhost:5432/mydb
BOT_TOKEN=123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ
DEBUG=True



Критически важно: файл .env должен быть обязательно добавлен в ваш файл .gitignore, чтобы он ни при каких обстоятельствах не попал в Git. Для команды вместо этого создают файл-шаблон .env.example, где оставляют только названия переменных без реальных секретных данных.

Зачем это инженеру? Это делает приложение гибким и безопасным. В экосистеме Python для удобной работы с переменными окружения используют библиотеки вроде python-dotenv или встроенные механизмы Pydantic (pydantic-settings).

Пример чтения переменных в коде Python:

import os
from dotenv import load_dotenv

# Загружаем переменные из файла .env в окружение
load_dotenv()

# Достаем значения
db_url = os.getenv("DATABASE_URL")
bot_token = os.getenv("BOT_TOKEN")
# Второй аргумент — значение по умолчанию, если переменная не найдена
debug_mode = os.getenv("DEBUG", "False") == "True"



Такой подход позволяет использовать один и тот же код в разных средах без его изменения. Локально на компьютере вы используете .env с тестовой базой данных, на стейджинг-сервере прописываете другие значения, а на продакшене — боевые доступы (задавая их через настройки Docker, Systemd или панели управления сервером).

Разделение конфигурации и кода — это один из главных принципов современной разработки (часть методологии *Twelve-Factor App*). Это гарантирует безопасность ваших данных и упрощает масштабирование проекта.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
4
⚡️Группа хакеров взломала сервера Skillbox, Geekbrains, Skillfactory и ещё 12 онлайн-школ, чтобы выгрузить их курсы в Telegram

Юристы пытаются удалить каналы за Авторские Права🤡 – потому вот актуальные ссылки на архивы:

По школам: 

Skillbox (1.12 ТБ)
├ Нетология (846 ГБ)
├ SkillFactory (720 ГБ) 
├ GeekBrains (934 ГБ)
└ Другие (3.21 ТБ)

По ЯП:

Python (1.48 ТБ)
SQL (982 ГБ)
C++ (590 ГБ)
С (318 ГБ)
GoLang (290 ГБ)
Другие (3.17 ТБ)

Ссылка на общий архив: @schools_hack_arc
👎13😁7
📡 Протокол WebSocket — двусторонняя связь в реальном времени

Классический HTTP работает по принципу «запрос-ответ»: клиент (браузер) просит данные, сервер их отдает, и соединение закрывается. Но что делать, если вам нужно построить чат, онлайн-игру или живой график котировок криптовалют? Заставлять браузер каждую секунду слать HTTP-запросы — дико неэффективно. Для таких задач используют протокол WebSocket.

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

Как устроен жизненный цикл WebSocket:
Handshake (Рукопожатие): Клиент отправляет обычный HTTP-запрос с особыми заголовками, говоря серверу: «Давай перейдем на WebSocket».
Upgrade: Если сервер согласен, соединение «апгрейдится» (статус код 101 Switching Protocols).
Двусторонний обмен: Канал открыт. Теперь данные летают туда и обратно в виде легких фреймов.
Закрытие: Любая сторона может закрыть соединение в любой момент.

Зачем это инженеру? Ради мгновенной реакции и экономии ресурсов. В HTTP каждый запрос тянет за собой кучу служебной информации (куки, заголовки браузера, тип контента), которая может весить больше, чем полезные данные. В WebSocket после установки соединения накладные расходы составляют всего несколько байт на сообщение.

В экосистеме Python работать с WebSocket невероятно удобно через фреймворк FastAPI. Он из коробки предоставляет простой синтаксис для управления такими соединениями.

Пример простейшего WebSocket-сервера на FastAPI:

from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept() # Принимаем соединение
while True:
# Ждем сообщение от клиента
data = await websocket.receive_text()
# Тут же отправляем ответ назад
await websocket.send_text(f"Сервер получил: {data}")



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

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
7
Не крипта, не мемкоины, не казино

🥇 Твой пассивный доход должен строиться на понятных активах
А не на СКАМерских проектах-однодневках.

Notal 📈 — канал о том, как зарабатывать на автоматической торговле золотом и серебром без вечной жизни на графиках.

Начните с простого: получите БЕСПЛАТНУЮ версию робота с доходностью до 25% годовых. Без подписок. Без настроек.
🤖 SilentGain

Как возможны 25% годовых? Узнай⤵️
https://t.me/+SZaP3SGi1uZjNzYy
😁3👍1
🥒 Кэширование на стероидах — зачем использовать Redis Hash?

Когда разработчики начинают работать с Redis, они обычно используют его как простое хранилище строк: записывают объект пользователя в виде JSON-строки по ключу user:100 через команду SET. Но если вам нужно обновить всего одно поле (например, статус или баланс), приходится доставать всю строку, десериализовать её, менять значение, собирать обратно в JSON и перезаписывать. Это медленно и неэффективно. Для работы со сложными объектами в Redis есть идеальная структура — Hash (Хэш).

Хэши в Redis — это полноценные словари внутри базы данных. Они позволяют хранить под одним ключом множество пар «поле-значение». Вы получаете структуру вида Ключ -> [Поле1: Значение1, Поле2: Значение2], которой можно управлять точечно.

Основные команды для работы с Хэшами:
Записать объект: HSET user:100 username "alex" status "active" age 25
Получить конкретное поле: HGET user:100 status
Получить весь объект: HGETALL user:100
Увеличить числовое поле: HINCRBY user:100 age 1 (идеально для счетчиков)
Удалить одно поле: HDEL user:100 age

Зачем это инженеру? Ради колоссальной экономии памяти и процессорного времени. Когда вы используете Redis Hash, бэкенду на Python или JS больше не нужно тратить ресурсы на постоянный парсинг строк туда-обратно. Вы можете обновить статус пользователя одной быстрой командой, не трогая остальные данные.

Кроме того, под капотом Redis оптимизирует хранение маленьких хэшей с помощью структуры ziplist (компактный список). Это позволяет хранить миллионы объектов, тратя на них в разы меньше оперативной памяти, чем если бы каждый из них был отдельной JSON-строкой.

Использование хэшей — это стандартный паттерн для хранения профилей пользователей, настроек конфигурации, корзин товаров в интернет-магазинах или текущего состояния игровых сессий.

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

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
📬 Брокеры сообщений — зачем вашему проекту Celery и RabbitMQ?

Когда пользователь нажимает кнопку «Зарегистрироваться», ваш бэкенд должен сделать много дел: создать запись в базе данных, сгенерировать тяжелый PDF-договор, загрузить аватарку в облако и отправить приветственное письмо на почту. Если делать всё это в основном потоке веб-запроса, пользователь будет секунд 10 смотреть на крутящийся лоадер. Чтобы этого избегать, тяжелые задачи уводят в фоновый режим с помощью очередей задач.

---

Для реализации такой схемы нужна связка из двух компонентов: Брокера сообщений (например, RabbitMQ или Redis) и Воркера (в мире Python это чаще всего Celery).

Как устроена эта цепочка:
Веб-приложение (Producer): Быстро сохраняет юзера в базу, кидает короткую задачу вроде «отправь письмо юзеру №42» в брокер и тут же возвращает пользователю ответ 200 OK. Для юзера всё произошло мгновенно.
Брокер сообщений (RabbitMQ): Принимает эту задачу, складывает её в очередь и хранит, пока освободится исполнитель.
Воркер (Celery Worker): Постоянно слушает брокер, забирает задачу из очереди и спокойно выполняет её на фоне, не мешая основному сайту.

Зачем это инженеру? Это кардинально повышает живучесть и скорость системы. Если сторонний сервис отправки писем вдруг «приляжет», ваше приложение не упадет. RabbitMQ сохранит задачу в очереди, а Celery будет пытаться отправить её снова и снова, пока сервис не оживет. Пользователь об этих проблемах даже не узнает.

Пример кода на Python с использованием Celery:

from celery import Celery

# Инициализируем Celery и указываем RabbitMQ в качестве брокера
app = Celery('tasks', broker='amqp://guest@localhost//')

@app.task
def send_welcome_email(user_id):
# Тут логика генерации PDF и отправки тяжелого письма
print(f"Письмо для пользователя {user_id} успешно отправлено!")



В основном коде FastAPI или Django вы вызываете эту функцию не напрямую, а через специальный метод: send_welcome_email.delay(user_id). Слово .delay() как раз и дает команду не выполнять код здесь и сейчас, а упаковать аргументы в сообщение и забросить их в RabbitMQ.

Использование Celery и RabbitMQ — это стандарт построения масштабируемых и отказоустойчивых систем. Это позволяет легко распределять нагрузку: если задач стало слишком много, вы можете просто запустить еще несколько воркеров Celery на соседних серверах, не меняя ни единой строчки в коде самого сайта.
2
🛡️ Мидлвары — как фильтровать веб-запросы на подлете к коду?

Представьте, что у вас в приложении на FastAPI, Django или Node.js есть 50 разных эндпоинтов. Для каждого из них нужно проверять, авторизован ли пользователь, логировать время обработки запроса и добавлять защитные заголовки. Писать этот код вручную внутри каждой функции — кошмар для поддержки. Чтобы решать такие сквозные задачи в один клик, используют Middleware (промежуточное ПО).

Мидлварь — это специальный слой-перехватчик, который встает прямо на пути сетевого запроса от клиента к вашему основному коду (роутам) и на обратном пути ответа от сервера к клиенту.

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

Как устроен жизненный цикл запроса с Middleware:
Клиент отправляет запрос к серверу.
Middleware 1 (Логирование): Записывает время старта и IP-адрес клиента, передает запрос дальше.
Middleware 2 (Авторизация): Достает токен из заголовков. Если токен битый — мидлварь сразу разворачивает запрос назад и отдает ошибку 401 Unauthorized, даже не беспокоя основной код приложения.
Ваш код (Роут): Если всё ок, выполняется логика приложения (например, выдача списка товаров) и формируется ответ.
Обратный путь: Ответ снова летит через все мидлвари в обратном порядке. Например, слой безопасности может прикрепить к нему CORS-заголовки.

Зачем это инженеру? Это идеальное воплощение принципа DRY (Don't Repeat Yourself). Вместо дублирования проверок безопасности, вы выносите их на глобальный уровень.

Пример кастомной мидлвари для подсчета времени запроса на FastAPI:

import time
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()

# Передаем запрос дальше по цепочке к роуту
response = await call_next(request)

# Этот код выполнится уже на обратном пути ответа
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)

return response



Встроенные мидлвари есть во всех популярных фреймворках. Самый частый пример — CORSMiddleware, который разрешает или запрещает вашему фронтенду, запущенному на другом домене, делать запросы к бэкенду. Без него браузер просто заблокирует любые попытки забрать данные.

Использование Middleware позволяет держать ваш основной код чистым, фокусируясь только на бизнес-логике. Все системные задачи — проверка токенов, сжатие ответов (Gzip), защита от атак и сбор метрик — делегируются этим невидимым стражам на входе в систему.

🚪 Bash Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4