Статья в формате шпаргалки — для тех, кто понимает, о чём тут речь и зачем оно нужно. Я бы был очень рад, если бы такая была у меня вчера. Здесь максимально кратко изложен мой опыт, без воды и лишних отступлений. В итоге пополучим полностью готовую инфраструктуру под свои проекты на n8n.
Конечно, статей «как развернуть n8n на своём сервере» полно. Если эта кажется такой же — значит, либо вы не целевой читатель, либо я чего‑то не понимаю.
Пункт 0
Берем в аренду простенький сервак (я тестил на 2cpu, 2gb ram. Уверен, что и на 1cpu нормально будет). Привязываем к нему домен в dns, я использую поддомен третьего уровня на своем личном домене для pet проектов.
Для бекапов берём S3-совместимое хранилище. Стоить будет примерно 0 рублей, если не хранить гигабайты (а мы не будем).
В итоге: сервак ≈ двойная шавы в месяц, домен ≈ один капучино в год.А на выходе — полная свобода для своих проектов, автоматизаций, ботов и всего, что можно накрутить на n8n.
n8n
Ставим Docker и Docker Compose:
sudo apt update
sudo apt install -y ca-certificates curl gnupg
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Создаём ./n8n и кладём туда конфиг docker-compose.yml:
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
ports:
- "5678:5678"
environment:
- N8N_PORT=5678
- N8N_PROTOCOL=http
- N8N_HOST={ваш_домен}
- WEBHOOK_URL=https://{ваш_домен}
volumes:
- ./data:/home/node/.n8n
restart: always
Замените {ваш_домен} на свой (например n8n.example.com).
Перед запуском создаём папку под хранилище n8n и выдаём правильные права:
mkdir -p ~/n8n/data
sudo chown -R 1000:1000 ~/n8n/data
Запуск:
docker compose up -d
docker ps
nginx
Создаём конфиг под наш домен:
sudo nano /etc/nginx/sites-available/{ваш_домен}
Вставляем:
server {
listen 80;
server_name {ваш_домен};
location / {
proxy_pass http://localhost:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# --- ВАЖНО: WebSocket ---
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
}
}
WebSocket нужен, чтобы интерфейс n8n в браузере мог работать с сервером.
Активируем конфиг:
sudo ln -s /etc/nginx/sites-available/{ваш_домен} /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Ставим SSL:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d {ваш_домен}
? Всё - n8n работает на вашем домене.
postgres
Можно, конечно, использовать встроенную бдшку в n8n, но яйца в одну корзину не кладём.Да и хочется всё по красоте: отдельная бд, бекапы, проекты — как у больших дядь.
Готовим структуру:
mkdir -p ~/postgres
cd ~/postgres
mkdir data
Создаём docker-compose.yml:
version: "3.8"
services:
postgres:
image: postgres:16
restart: always
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: {ваш_пароль}
ports:
- "5432:5432"
volumes:
- ./data:/var/lib/postgresql/data
Запускаем:
docker compose up -d
docker ps
Небольшое наставление: на каждый проект — отдельная база и отдельный пользователь с правами только на свою базу.
Подключаемся:
docker exec -it postgres-postgres-1 psql -U admin
Создаём базу:
CREATE DATABASE project1;
Создаём пользователя:
CREATE USER project1_user WITH PASSWORD '{ваш_пароль}';
GRANT ALL PRIVILEGES ON DATABASE project1 TO project1_user;
Бекапы
Бекапим и базу, и данные n8n — чтобы и воркфлоу наши бекапились и мы ничего не потеряли точно.
Будем работать через MinIO Client (mc).
Ставим:
wget https://dl.min.io/client/mc/release/linux-amd64/mc -O /usr/local/bin/mc
chmod +x /usr/local/bin/mc
Создаём подключение:
mc alias set beget https://{URL\\_S3} {ACCESS_KEY} {SECRET_KEY} --api S3v4
Пример:
mc alias set beget https://s3.ru1.storage.beget.cloud KXXX SXXX --api S3v4
Проверяем:
mc ls beget/
Создаём ~/backup.sh:
DATE=$(date +"%Y-%m-%d_%H-%M")
BUCKET="{имя бакета}"
TELEGRAM_BOT_TOKEN="ТОКЕН"
TELEGRAM_CHAT_ID="ID"
send_telegram() {
MESSAGE="$1"
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
-d chat_id="$TELEGRAM_CHAT_ID" \
-d text="$MESSAGE" \
-d parse_mode="Markdown" \
-d disable_notification=true
}
# --- Backup PostgreSQL ---
echo "Dumping PostgreSQL..."
docker exec postgres-postgres-1 pg_dumpall -U admin | gzip > /tmp/pg_backup_$DATE.sql.gz
if [ -f "/tmp/pg_backup_$DATE.sql.gz" ]; then
mc cp /tmp/pg_backup_$DATE.sql.gz beget/$BUCKET/postgres/
rm /tmp/pg_backup_$DATE.sql.gz
PG_STATUS="PostgreSQL backup: OK"
else
PG_STATUS="PostgreSQL backup: FAILED"
fi
# --- Backup n8n ---
echo "Backing up n8n..."
tar -czf /tmp/n8n_backup_$DATE.tar.gz ~/n8n/data
if [ -f "/tmp/n8n_backup_$DATE.tar.gz" ]; then
mc cp /tmp/n8n_backup_$DATE.tar.gz beget/$BUCKET/n8n/
rm /tmp/n8n_backup_$DATE.tar.gz
N8N_STATUS="n8n backup: OK"
else
N8N_STATUS="n8n backup: FAILED"
fi
# --- Clean old backups (older than 14 days) ---
for file in $(mc ls beget/$BUCKET/postgres/ | awk '$1 < strftime("%Y-%m-%d", systime() - 1209600) {print $5}'); do
mc rm beget/$BUCKET/postgres/$file
done
for file in $(mc ls beget/$BUCKET/n8n/ | awk '$1 < strftime("%Y-%m-%d", systime() - 1209600) {print $5}'); do
mc rm beget/$BUCKET/n8n/$file
done
# --- SEND TELEGRAM NOTIFICATION ---
MESSAGE="Бэкап завершён
$PG_STATUS
$N8N_STATUS"
send_telegram "$MESSAGE"
echo "Backup completed!"
Делаем исполняемым:
chmod +x ~/backup.sh
./backup.sh
Если в телеге пришло - всё ок.
cron для бекапов
Настраиваем запуск каждые 6 часов:
crontab -e
Добавляем:
0 */6 * * * /bin/bash /root/backup.sh >> /root/backup.log 2>&1
Готово. Теперь у вас:
n8n
отдельная PostgreSQL
домен
SSL
автоматические бекапы в S3
уведомления в Telegram
webhamster
Эмм... Утилита mc - это не Midnight Commander, а что-то другое? Насколько удобно работать в консоли и вызывать mc, если у тебя два разных mc?
IvanNoskov Автор
Оу, действительно есть такое, мне даже не бросилось в глаза сразу, коммандер давно не использовал. Утилиту выбрал потому что она нормально с первого раза завелась с несколькими разными s3, в том числе с beget`овским. aws cli отказывался с ним работать сколько не пытался. Если вопрос про личный опыт, то командер не использую, тем более контекст предполагает что мы ставим всё это добро из статьи на чистый сервак под наши задачи. Если вопрос общий, то сконфигурировать bash не проблема