Создайте Your Own Передача файлов Service: Dev Руководство
Создайте a файл transfer service from scratch. Backend API design, storage integration, и user interface development tutorial.
Чтобы создать собственный сервис передачи файлов, вам нужно пять компонентов: фронтенд, который нарезает и опционально шифрует файлы в браузере; REST API, который создаёт сессии загрузки и формирует предподписанные URL хранилища; S3-совместимое объектное хранилище (Cloudflare R2, Backblaze B2 или MinIO); небольшая база метаданных (SQLite или Postgres); и TLS 1.3 reverse proxy. На Node 22, Fastify и Vite можно выпустить сервис в духе WeTransfer примерно в 600 строк кода и хостить всё это за $5–15 в месяц при умеренном трафике.
Начните с выбора слоя хранилища
Экономика хранилища определяет судьбу сервиса передачи файлов. AWS S3 берёт $0,09 за ГБ исходящего трафика — значит, популярная загрузка на 2 ГБ, скачанная 1 000 раз, обойдётся вам в $180 только на пропускную способность. Cloudflare R2 не берёт за исходящий и берёт $0,015 за ГБ хранения. Backblaze B2: $0,01 за ГБ исходящего и $0,006 за ГБ хранения. Для бесплатного сервиса передачи R2 — очевидный выбор. MinIO позволяет вам размещать S3-семантику на собственном железе — подходит, если у вас уже есть простаивающая полоса и диски.
Используйте предподписанные URL, чтобы клиенты загружали и скачивали напрямую из хранилища, минуя ваш сервер. Это делает API CPU-нагруженным, а не bandwidth-нагруженным.
Набросок поверхности API
Держите API небольшим. Пять эндпоинтов покрывают 95% потребностей:
POST /sessions— создать сессию загрузки, вернуть ID и предподписанные URL для составной загрузкиPOST /sessions/:id/complete— завершить составную загрузку, вернуть URL ссылкиGET /shares/:id— вернуть метаданные файла (размер, срок, оставшиеся загрузки)GET /shares/:id/download— вернуть предподписанный URL скачиванияDELETE /shares/:id— позволить владельцу отозвать доступ досрочно (требует токен отзыва)
Жёстко ограничьте POST /sessions по скорости — 20 в час с одного IP вполне достаточно. Все эндпоинты возвращают JSON, используют Cache-Control: no-store и устанавливают Content-Security-Policy на HTML-страницах.
Подключение бэкенда с Fastify
Fastify даёт валидацию JSON-схем, разумное логирование и 30 000 запросов в секунду на ядро без лишних усилий. Минимальный POST /sessions:
fastify.post('/sessions', {
schema: {
body: {
type: 'object', required: ['size'],
properties: {
size: { type: 'integer', minimum: 1, maximum: 10737418240 },
contentType: { type: 'string', maxLength: 120 }
}
}
}
}, async (req) => {
const id = nanoid(16);
const key = `blobs/${id}`;
const upload = await s3.createMultipartUpload({
Bucket: 'transfers', Key: key, ContentType: req.body.contentType
});
const partCount = Math.ceil(req.body.size / (8 * 1024 * 1024));
const urls = await Promise.all(
Array.from({ length: partCount }, (_, i) =>
getSignedUrl(s3, new UploadPartCommand({
Bucket: 'transfers', Key: key, UploadId: upload.UploadId, PartNumber: i + 1
}), { expiresIn: 3600 }))
);
db.prepare('INSERT INTO sessions VALUES (?, ?, ?, ?)')
.run(id, upload.UploadId, key, Date.now());
return { id, uploadId: upload.UploadId, partUrls: urls };
});
Потолок 10 ГБ, части по 8 МБ, срок действия URL 1 час. Корректируйте под структуру вашего трафика.
Создание UI загрузки
Vite + React + без UI-библиотек — примерно 150 строк до работающего drag-and-drop. Ключевой элемент — воркер загрузки: создайте выделенный Web Worker, передайте ему хэндл File и URL частей, пусть он PUT-ит каждый чанк с параллельностью 3. Главный поток остаётся отзывчивым, обновления прогресса приходят через postMessage.
// worker.js
self.onmessage = async ({ data: { file, partUrls } }) => {
const partSize = 8 * 1024 * 1024;
const etags = [];
for (let i = 0; i < partUrls.length; i++) {
const blob = file.slice(i * partSize, (i + 1) * partSize);
const res = await fetch(partUrls[i], { method: 'PUT', body: blob });
etags[i] = res.headers.get('etag');
self.postMessage({ type: 'progress', done: i + 1, total: partUrls.length });
}
self.postMessage({ type: 'done', etags });
};
Добавьте поле пароля, которое получает ключ через PBKDF2 (600 000 итераций, SHA-256) и пропускает каждый чанк через AES-256-GCM перед PUT. Это превращает ваш сервис из серверно-шифрованного в E2EE.
Проектирование схемы базы данных
SQLite через better-sqlite3 обрабатывает десятки миллионов строк без проблем. Держите схему компактной:
CREATE TABLE sessions (
id TEXT PRIMARY KEY, upload_id TEXT, object_key TEXT, created_at INTEGER
);
CREATE TABLE shares (
id TEXT PRIMARY KEY, object_key TEXT, size_bytes INTEGER,
content_type TEXT, expires_at INTEGER, max_downloads INTEGER,
download_count INTEGER DEFAULT 0, revocation_token TEXT
);
CREATE INDEX idx_shares_expires ON shares(expires_at);
Никакой таблицы пользователей, никаких email, никаких IP-логов. Это намеренное решение — оно делает соответствие требованиям 152-ФЗ (и GDPR) почти тривиальным. Ночной крон удаляет истёкшие строки и их объекты S3:
const expired = db.prepare('SELECT object_key FROM shares WHERE expires_at < ?').all(Date.now());
for (const { object_key } of expired) {
await s3.deleteObject({ Bucket: 'transfers', Key: object_key });
}
db.prepare('DELETE FROM shares WHERE expires_at < ?').run(Date.now());
Реализация ссылок и скачиваний
URL ссылок выглядят как https://yourapp.com/f/abc123#k=<base64key> при добавлении клиентского шифрования. Фрагмент не попадает в серверные логи. Страница скачивания получает /shares/abc123, берёт предподписанный URL S3, стримит байты напрямую из R2, расшифровывает в браузере и передаёт результат в StreamSaver.js или File System Access API.
Установите Content-Disposition: attachment; filename*=UTF-8''encoded-name, чтобы браузер открывал диалог сохранения, а не рендерил файл встроенно. Это важно для PDF, HTML и SVG — все они могут выполнять скрипты в браузере в противном случае.
Защита от злоупотреблений
Сервисы передачи файлов привлекают злоумышленников. Ждите три категории: распространение вредоносного ПО, фишинговые нагрузки и загрузки с нарушением авторских прав. Меры защиты по убыванию эффективности: ограничение скорости загрузок по IP, минимальный размер файла (менее 10 КБ — почти всегда мусор), вычисление SHA-256 шифротекста и проверка по списку блокировки известных нежелательных хешей, форма для жалоб на злоупотребления без лишних шагов. ClamAV на расшифрованном контенте работает только при наличии ключа, что нарушает E2EE — правильный ответ: контентно-агностичные лимиты скорости и оперативные удаления по жалобам.
Подписывайте каждый предподписанный URL с коротким TTL (максимум 1 час) и привязывайте сессии к сгенерированному браузером эфемерному токену в Secure; HttpOnly; SameSite=Strict куки.
Дешёвое развёртывание и эксплуатация
Один Hetzner CX22 за $10 (2 vCPU, 4 ГБ RAM) запускает Fastify + SQLite + Caddy reverse proxy и обслуживает тысячи активных пользователей. Caddy автоматически обеспечивает TLS 1.3 через Let's Encrypt. Поставьте Cloudflare перед ним для защиты от DDoS и бесплатного WAF. Мониторинг через Uptime Kuma (бесплатно, self-hosted), логи в stdout, захватываемый journald.
Для географической избыточности реплицируйте SQLite через Litestream в R2 и направьте второй регион на то же хранилище объектов. Переключение при сбое — на уровне DNS. Вся история о DR умещается на салфетке.
Описанный подход во многом повторяет архитектуру HexaTransfer — Fastify API, R2-хранилище, Web Crypto в браузере, SQLite-метаданные, без аккаунтов. Попробуйте на hexatransfer.com — бесплатно, без аккаунта, до 10 ГБ.
Что пропустить до момента, когда оно понадобится
Не делайте аккаунты, команды и папки в v1. Не добавляйте отправку email. Не реализуйте предпросмотр видео или миниатюры изображений — оба вынуждают сервер видеть открытый текст. Не выпускайте мобильное приложение, пока веб-версия не будет безупречна на мобильном Safari. Функциональное раздутие, убившее ранние клоны сервисов передачи файлов, всегда следовало одному паттерну: аккаунты, затем квоты, затем оплата, затем командные планы — и вот вы уже конкурируете с Dropbox вместо того, чтобы выпускать быстрый, приватный инструмент передачи. Держите поверхность небольшой, а криптографию — строгой.
Безопасная отправка больших файлов со сквозным шифрованием
Передавайте файлы до 10 ГБ бесплатно со сквозным шифрованием. Регистрация не требуется. Ваши файлы шифруются в браузере перед загрузкой — никто другой не может их прочитать.
Отправить файл