Статья в формате шпаргалки — для тех, кто понимает, о чём тут речь и зачем оно нужно. Я бы был очень рад, если бы такая была у меня вчера. Здесь максимально кратко изложен мой опыт, без воды и лишних отступлений. В итоге пополучим полностью готовую инфраструктуру под свои проекты на 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?