[{"data":1,"prerenderedAt":150},["ShallowReactive",2],{"$f2n4ktxqedg8ls":3,"articles":48},{"slug":4,"title":5,"description":6,"date":7,"updated":7,"tags":8,"emoji":13,"minutes":14,"html":15,"headings":16},"kak-razvernut-sait-na-vps","Как развернуть сайт на VPS","Пошаговый путь для Ubuntu LTS от пользователя и SSH-ключа до Caddy с HTTPS, запуска через pm2, логов, обновлений и бэкапов.","2026-10-01",[9,10,11,12],"vps","ubuntu","node","caddy","rocket",4,"\u003Ch2 id=\"korotko\">Коротко\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Команды рассчитаны на свежий сервер с Ubuntu LTS (например, 24.04 или 26.04). Перед каждой командой поймите, что она делает.\u003C\u002Fli>\n\u003Cli>Порядок: отдельный пользователь с SSH-ключом, файрвол, Node.js, сборка, запуск через pm2, Caddy с HTTPS.\u003C\u002Fli>\n\u003Cli>Приложение слушает только \u003Ccode>127.0.0.1\u003C\u002Fcode>, наружу смотрит Caddy.\u003C\u002Fli>\n\u003Cli>A-записи для домена и \u003Ccode>www\u003C\u002Fcode> на IP сервера создайте заранее.\u003C\u002Fli>\n\u003Cli>Сразу продумайте обновления и бэкапы.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"chto-ponadobitsya\">Что понадобится\u003C\u002Fh2>\n\u003Cp>VPS с Ubuntu LTS, его IP (ниже \u003Ccode>203.0.113.10\u003C\u002Fcode>), домен (ниже \u003Ccode>example.com\u003C\u002Fcode>) и SSH-клиент. Создайте в самом начале A-запись для \u003Ccode>@\u003C\u002Fcode> на IP сервера и запись для \u003Ccode>www\u003C\u002Fcode> (A на тот же IP или CNAME на \u003Ccode>example.com\u003C\u002Fcode>). Пока идёт настройка, DNS успеет обновиться. Подробности в статье \u003Ca href=\"\u002Farticles\u002Fkak-privyazat-domen-k-hostu\">как привязать домен к хостингу\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"1-polzovatel-i-ssh-klyuch\">1. Пользователь и SSH-ключ\u003C\u002Fh2>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-comment\"># на своём компьютере\u003C\u002Fspan>\nssh root@203.0.113.10\n\n\u003Cspan class=\"hljs-comment\"># на сервере под root\u003C\u002Fspan>\napt update &amp;&amp; apt upgrade -y\nadduser deploy\nusermod -aG \u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> deploy\nrsync --archive --\u003Cspan class=\"hljs-built_in\">chown\u003C\u002Fspan>=deploy:deploy ~\u002F.ssh \u002Fhome\u002Fdeploy\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Последняя команда копирует ключ, добавленный при создании сервера. Если ключа нет, создайте его на своём компьютере (\u003Ccode>ssh-keygen -t ed25519\u003C\u002Fcode>) и добавьте через \u003Ccode>ssh-copy-id deploy@203.0.113.10\u003C\u002Fcode> (в Windows эта команда есть в Git Bash и WSL) либо вставьте содержимое файла \u003Ccode>id_ed25519.pub\u003C\u002Fcode> в \u003Ccode>~\u002F.ssh\u002Fauthorized_keys\u003C\u002Fcode> пользователя \u003Ccode>deploy\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Во втором окне проверьте вход \u003Ccode>ssh deploy@203.0.113.10\u003C\u002Fcode> и выполните \u003Ccode>sudo whoami\u003C\u002Fcode>. Рабочую сессию не закрывайте, пока не убедитесь, что вход по ключу работает.\u003C\u002Fp>\n\u003Cp>Только после этого в \u003Ccode>\u002Fetc\u002Fssh\u002Fsshd_config\u003C\u002Fcode> задайте \u003Ccode>PermitRootLogin no\u003C\u002Fcode> и \u003Ccode>PasswordAuthentication no\u003C\u002Fcode> и выполните \u003Ccode>sudo systemctl restart ssh\u003C\u002Fcode>. Проверьте итог: \u003Ccode>sudo sshd -T | grep -Ei &#39;permitrootlogin|passwordauthentication&#39;\u003C\u002Fcode>. Если где-то всё ещё yes, ищите переопределения в \u003Ccode>\u002Fetc\u002Fssh\u002Fsshd_config.d\u002F\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"2-fayrvol\">2. Файрвол\u003C\u002Fh2>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow OpenSSH\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow 80\u002Ftcp\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow 443\u002Ftcp\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw \u003Cspan class=\"hljs-built_in\">enable\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Правило для SSH добавляйте до включения, иначе потеряете доступ. Если у провайдера есть собственный файрвол, откройте там те же порты.\u003C\u002Fp>\n\u003Ch2 id=\"3-node-js\">3. Node.js\u003C\u002Fh2>\n\u003Cp>Пакет \u003Ccode>nodejs\u003C\u002Fcode> из репозитория Ubuntu часто отстаёт от актуальной LTS. Откройте \u003Ca href=\"https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\" target=\"_blank\" rel=\"noopener noreferrer\">https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\u003C\u002Fa>, выберите Linux и версию с пометкой LTS и выполните команды со страницы (для Linux там обычно предлагается nvm). Команды вида \u003Ccode>curl ... | bash\u003C\u002Fcode> запускают код из интернета, поэтому берите их только со страниц разработчиков. После установки откройте новую SSH-сессию и проверьте \u003Ccode>node -v\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"4-prilozhenie\">4. Приложение\u003C\u002Fh2>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">git \u003Cspan class=\"hljs-built_in\">clone\u003C\u002Fspan> https:\u002F\u002Fgithub.com\u002F&lt;user&gt;\u002F&lt;repo&gt;.git mysite\n\u003Cspan class=\"hljs-built_in\">cd\u003C\u002Fspan> mysite\nnpm ci\nnpm run build\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Для приватного репозитория используйте deploy key только на чтение, а не личный ключ. Секреты храните в переменных окружения или в файле с правами \u003Ccode>chmod 600\u003C\u002Fcode>, но не в git. На серверах с 1 ГБ памяти и меньше сборка может упасть: соберите проект у себя и загрузите результат или добавьте swap.\u003C\u002Fp>\n\u003Ch2 id=\"5-zapusk-cherez-pm2\">5. Запуск через pm2\u003C\u002Fh2>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">npm install -g pm2\nNITRO_HOST=127.0.0.1 NITRO_PORT=3000 pm2 start .output\u002Fserver\u002Findex.mjs --name mysite\npm2 startup\npm2 save\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Так запускается Nuxt, а другие приложения стартуют по-своему. Главное, чтобы приложение слушало \u003Ccode>127.0.0.1\u003C\u002Fcode> и известный порт. Команду, которую напечатает \u003Ccode>pm2 startup\u003C\u002Fcode> (она уже начинается с sudo), скопируйте и выполните: тогда сайт поднимется после перезагрузки. Вместо pm2 можно использовать службу systemd, пример в статье \u003Ca href=\"\u002Farticles\u002Fkak-zapustit-telegram-bota-na-servere\">как запустить Telegram бота на сервере\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"6-caddy-i-https\">6. Caddy и HTTPS\u003C\u002Fh2>\n\u003Cp>Установите Caddy из официального репозитория. Команды ниже взяты со страницы \u003Ca href=\"https:\u002F\u002Fcaddyserver.com\u002Fdocs\u002Finstall\" target=\"_blank\" rel=\"noopener noreferrer\">https:\u002F\u002Fcaddyserver.com\u002Fdocs\u002Finstall\u003C\u002Fa> (раздел Debian, Ubuntu), при расхождениях верьте ей:\u003C\u002Fp>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> apt install -y debian-keyring debian-archive-keyring apt-transport-https curl\ncurl -1sLf \u003Cspan class=\"hljs-string\">&#x27;https:\u002F\u002Fdl.cloudsmith.io\u002Fpublic\u002Fcaddy\u002Fstable\u002Fgpg.key&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fcaddy-stable-archive-keyring.gpg\ncurl -1sLf \u003Cspan class=\"hljs-string\">&#x27;https:\u002F\u002Fdl.cloudsmith.io\u002Fpublic\u002Fcaddy\u002Fstable\u002Fdebian.deb.txt&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> \u003Cspan class=\"hljs-built_in\">tee\u003C\u002Fspan> \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fcaddy-stable.list\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> \u003Cspan class=\"hljs-built_in\">chmod\u003C\u002Fspan> o+r \u002Fusr\u002Fshare\u002Fkeyrings\u002Fcaddy-stable-archive-keyring.gpg\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> \u003Cspan class=\"hljs-built_in\">chmod\u003C\u002Fspan> o+r \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fcaddy-stable.list\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> apt update\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> apt install caddy\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Затем откройте файл от имени администратора (\u003Ccode>sudo nano \u002Fetc\u002Fcaddy\u002FCaddyfile\u003C\u002Fcode>), замените содержимое и перезагрузите службу:\u003C\u002Fp>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-text\">example.com, www.example.com {\n    reverse_proxy 127.0.0.1:3000\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> systemctl reload caddy\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Caddy сам получит сертификат и включит редирект на HTTPS, если A-запись уже ведёт на сервер, а порты 80 и 443 открыты. Вместо Caddy можно взять nginx с \u003Ccode>proxy_pass http:\u002F\u002F127.0.0.1:3000;\u003C\u002Fcode> и выпустить сертификат через certbot, см. \u003Ca href=\"\u002Farticles\u002Fssl-sertifikat-https\">SSL сертификат и HTTPS\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"7-logi-obnovleniya-i-bekapy\">7. Логи, обновления и бэкапы\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Логи:\u003C\u002Fstrong> \u003Ccode>pm2 logs mysite\u003C\u002Fcode> и \u003Ccode>sudo journalctl -u caddy -n 50\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Обновления:\u003C\u002Fstrong> примерно раз в месяц выполняйте \u003Ccode>sudo apt update &amp;&amp; sudo apt upgrade\u003C\u002Fcode>. Если появился файл \u003Ccode>\u002Fvar\u002Frun\u002Freboot-required\u003C\u002Fcode>, перезагрузите сервер. Проверьте, что включены автоматические обновления безопасности (пакет \u003Ccode>unattended-upgrades\u003C\u002Fcode>).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Бэкапы:\u003C\u002Fstrong> снимки у провайдера, дамп базы данных и копия \u003Ccode>.env\u003C\u002Fcode> в надёжном месте, не только на этом сервере. Проверяйте, что восстановление работает.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"esli-ne-poluchilos\">Если не получилось\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Ccode>Permission denied\u003C\u002Fcode> при входе по SSH: неверный пользователь или ключ не скопирован. Проверьте \u003Ccode>~\u002F.ssh\u002Fauthorized_keys\u003C\u002Fcode> у \u003Ccode>deploy\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Сайт не открывается: на сервере проверьте \u003Ccode>sudo ufw status\u003C\u002Fcode>, \u003Ccode>pm2 status\u003C\u002Fcode> и \u003Ccode>curl -I http:\u002F\u002F127.0.0.1:3000\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Caddy не выпускает сертификат: A-запись ведёт не на этот сервер или закрыты порты 80 и 443 (в ufw либо у провайдера). Причина видна в \u003Ccode>sudo journalctl -u caddy\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Ошибка 502: приложение не запущено или слушает другой порт.\u003C\u002Fli>\n\u003Cli>Сборка падает с \u003Ccode>JavaScript heap out of memory\u003C\u002Fcode> или процесс убивается: не хватает памяти, см. шаг 4.\u003C\u002Fli>\n\u003Cli>После перезагрузки сайт не поднялся: вы не выполнили \u003Ccode>pm2 startup\u003C\u002Fcode> и \u003Ccode>pm2 save\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Если что-то непонятно, напишите мне в Telegram: @lztcoder\u003C\u002Fp>\n",[17,21,24,27,30,33,36,39,42,45],{"id":18,"text":19,"level":20},"korotko","Коротко",2,{"id":22,"text":23,"level":20},"chto-ponadobitsya","Что понадобится",{"id":25,"text":26,"level":20},"1-polzovatel-i-ssh-klyuch","1. Пользователь и SSH-ключ",{"id":28,"text":29,"level":20},"2-fayrvol","2. Файрвол",{"id":31,"text":32,"level":20},"3-node-js","3. Node.js",{"id":34,"text":35,"level":20},"4-prilozhenie","4. Приложение",{"id":37,"text":38,"level":20},"5-zapusk-cherez-pm2","5. Запуск через pm2",{"id":40,"text":41,"level":20},"6-caddy-i-https","6. Caddy и HTTPS",{"id":43,"text":44,"level":20},"7-logi-obnovleniya-i-bekapy","7. Логи, обновления и бэкапы",{"id":46,"text":47,"level":20},"esli-ne-poluchilos","Если не получилось",[49,57,66,75,85,95,103,108,110,121,129,136,142],{"slug":50,"title":51,"description":52,"date":7,"updated":7,"tags":53,"emoji":56,"minutes":14},"kak-vybrat-hosting","Как выбрать хостинг для сайта или бота","Чем отличаются виртуальный хостинг, VPS, облако и статический хостинг, сколько памяти нужно сайту и боту и что спросить у продавца.",[54,9,55],"хостинг","сервер","server",{"slug":58,"title":59,"description":60,"date":7,"updated":7,"tags":61,"emoji":65,"minutes":14},"kak-zapustit-telegram-bota-na-servere","Как запустить Telegram бота на сервере","Polling или webhook, где взять токен и как его защитить, как запускать бота через systemd, pm2 или Docker и что делать при сбоях.",[62,63,55,64],"telegram","бот","webhook","bot",{"slug":67,"title":68,"description":69,"date":7,"updated":7,"tags":70,"emoji":74,"minutes":14},"kak-kupit-domen","Как и где купить домен","Какую зону выбрать, что проверить перед оплатой, чем регистратор отличается от перепродавца и как не потерять домен.",[71,72,73],"домен","регистратор","dns","domain",{"slug":76,"title":77,"description":78,"date":7,"updated":7,"tags":79,"emoji":84,"minutes":14},"kak-oplatit-zakaz-kriptovalutoy","Как оплатить заказ криптовалютой","Как оплатить счёт из бота на странице Heleket, выбрать валюту и сеть, отправить точную сумму, проверить ссылку и действовать при ошибке.",[80,81,82,83],"оплата","криптовалюта","heleket","безопасность","pay",{"slug":86,"title":87,"description":88,"date":7,"updated":7,"tags":89,"emoji":93,"minutes":94},"kak-podgotovit-brif-dlya-sayta","Как подготовить бриф для сайта или бота","Что описать заранее, чтобы разработчик дал реалистичную оценку, от цели и аудитории до интеграций, срока и бюджета. Есть шаблон.",[90,91,63,92],"бриф","сайт","разработка","doc",3,{"slug":96,"title":97,"description":98,"date":7,"updated":7,"tags":99,"emoji":102,"minutes":14},"cloudflare-dlya-domena","Как подключить домен к Cloudflare","Как добавить домен в Cloudflare, сменить NS, выбрать режим SSL\u002FTLS и понять разницу между оранжевым и серым облаком.",[100,73,71,101],"cloudflare","ssl","cloud",{"slug":104,"title":105,"description":106,"date":7,"updated":7,"tags":107,"emoji":74,"minutes":14},"kak-privyazat-domen-k-hostu","Как привязать домен к хостингу","Что такое A-запись и NS, как подключить домен к хостингу или VPS и как проверить, что всё заработало.",[71,73,54],{"slug":4,"title":5,"description":6,"date":7,"updated":7,"tags":109,"emoji":13,"minutes":14},[9,10,11,12],{"slug":111,"title":112,"description":113,"date":7,"updated":7,"tags":114,"emoji":120,"minutes":14},"pochta-na-svoem-domene","Почта на своём домене: MX, SPF, DKIM, DMARC","Как подключить почту на своём домене, настроить MX, SPF, DKIM и DMARC, проверить доставку и понять, почему письма попадают в спам.",[115,116,117,118,119],"почта","mx","spf","dkim","dmarc","mail",{"slug":122,"title":123,"description":124,"date":7,"updated":7,"tags":125,"emoji":128,"minutes":14},"spamblok-telegram-chto-delat","Спамблок в Telegram: что это и что делать","Что такое ограничения аккаунта Telegram, как проверить статус через @SpamBot, как подать апелляцию и чего делать нельзя.",[62,126,127,83],"спамблок","аккаунт","help",{"slug":130,"title":131,"description":132,"date":7,"updated":7,"tags":133,"emoji":135,"minutes":14},"cloudflare-api-klyuch","Cloudflare: API токен и Global API Key","Чем API токен отличается от Global API Key в Cloudflare, какие права нужны для DNS, как выглядят запросы и что делать при утечке ключа.",[100,134,83],"api","key",{"slug":137,"title":138,"description":139,"date":7,"updated":7,"tags":140,"emoji":73,"minutes":14},"dns-zapisi-prostymi-slovami","DNS записи простыми словами","Что означают записи A, AAAA, CNAME, MX, TXT, NS, SRV и CAA, что такое TTL и почему CNAME нельзя поставить на корень домена.",[73,71,141],"записи",{"slug":143,"title":144,"description":145,"date":7,"updated":7,"tags":146,"emoji":149,"minutes":94},"ssl-sertifikat-https","SSL сертификат и HTTPS: как включить","Что даёт сертификат, как включить HTTPS через панель хостинга, Let's Encrypt с certbot, Caddy или Cloudflare и как проверить результат.",[101,147,148,83],"https","сертификат","shield",1791314128997]