Как установить EmDash на российский VPS без Cloudflare

Пошаговая установка EmDash CMS на свой сервер: Node.js, SQLite, nginx и HTTPS, обновления без простоя и резервные копии. Схема, на которой работает nesmachny.ru.

EmDash по умолчанию ориентирован на Cloudflare Workers, но запускается и на обычном сервере с Node.js. Для российских проектов это часто основной вариант: данные лежат в России, нет зависимости от доступности Cloudflare, а хостинг стоит несколько сотен рублей в месяц. По этой схеме работает nesmachny.ru и этот сайт.

Что понадобится

  • VPS с Ubuntu 22.04 или 24.04, от 2 ГБ памяти. Сборка Astro требует памяти, поэтому добавьте swap на 2–4 ГБ.
  • Node.js 22 и pnpm (через corepack).
  • nginx и certbot для HTTPS.
  • Домен, A-запись которого указывает на IP сервера.

1. Создайте проект

На своём компьютере выполните команду и выберите шаблон, например blog:

npm create emdash@latest

2. Переключите проект на Node.js и SQLite

В astro.config.mjs укажите адаптер Node, базу SQLite и хранение медиа в локальной папке:

astro.config.mjs
import node from "@astrojs/node";
import react from "@astrojs/react";
import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
  site: "https://example.ru",
  output: "server",
  outDir: process.env.ASTRO_OUT_DIR || "dist",
  adapter: node({ mode: "standalone" }),
  integrations: [
    react(),
    emdash({
      database: sqlite({ url: "file:./data.db" }),
      storage: local({ directory: "./uploads", baseUrl: "/_emdash/api/media/file" }),
    }),
  ],
});

Строка outDir понадобится для сборки без простоя, о ней ниже.

3. Подготовьте файл .env на сервере

.env
HOST=127.0.0.1
PORT=3013
NODE_ENV=production
SITE_URL=https://example.ru
EMDASH_SITE_URL=https://example.ru
EMDASH_ENCRYPTION_KEY=длинная-случайная-строка

Не пропускайте SITE_URL и EMDASH_SITE_URL. Без них EmDash строит адреса картинок с http://, и на HTTPS-сайте браузер блокирует их как смешанный контент. EMDASH_ENCRYPTION_KEY сгенерируйте один раз (например, openssl rand -base64 32) и не меняйте: им зашифрованы данные в базе.

4. Соберите и запустите

Скопируйте проект на сервер без node_modules, data.db и uploads, затем:

cd /var/www/example.ru
corepack pnpm install --frozen-lockfile
nice -n 19 corepack pnpm exec astro build
pm2 start dist/server/entry.mjs --name example --node-args="--env-file=.env"
pm2 save

При первом запуске EmDash создаст data.db и применит миграции.

5. Настройте nginx

/etc/nginx/sites-available/example.ru
upstream example_site {
  server 127.0.0.1:3013;
  keepalive 32;
}

server {
  listen 80;
  server_name example.ru www.example.ru;
  client_max_body_size 50m;

  location / {
    proxy_pass http://example_site;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Затем включите сайт и выпустите сертификат:

ln -s /etc/nginx/sites-available/example.ru /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d example.ru -d www.example.ru

6. Создайте администратора

Откройте https://example.ru/_emdash/admin и пройдите мастер первичной настройки. Сразу добавьте вход по ключу доступа (passkey): пока на сервере не настроена отправка почты, ссылки для входа по email приходить не будут.

Обновления без простоя

Если собирать проект прямо в dist, живой сайт несколько десятков секунд отдаёт ошибки. Собирайте в отдельную папку и подменяйте её одной командой:

ASTRO_OUT_DIR=dist.new nice -n 19 corepack pnpm exec astro build
rm -rf dist.old && mv dist dist.old && mv dist.new dist
pm2 restart example && rm -rf dist.old

Резервные копии

Весь контент хранится в двух местах: в файле data.db и в папке uploads. Копируйте базу командой SQLite, а не простым копированием файла, иначе можно потерять последние изменения из журнала:

sqlite3 /var/www/example.ru/data.db ".backup /var/backups/example/data-$(date +%F).db"
tar czf /var/backups/example/uploads-$(date +%F).tgz -C /var/www/example.ru uploads

Поставьте эти команды в cron раз в сутки. И никогда не удаляйте файл data.db-wal, пока сайт запущен: в нём лежат изменения, которые ещё не попали в основную базу.

Что дальше

Следующий шаг — перенос контента со старого сайта. Если не хотите заниматься этим сами, посмотрите миграцию под ключ.