<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>IceSlam</title><generator>teletype.in</generator><description><![CDATA[Официальный блог веб-разработчика
VueJS/NuxtJS, WordPress, MODX Revo, PHP, сервера]]></description><image><url>https://teletype.in/files/39/01/39015960-6fed-4435-82a7-345e2bffab85.png</url><title>IceSlam</title><link>https://teletype.in/@iceslam</link></image><link>https://teletype.in/@iceslam?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/iceslam?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/iceslam?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Mon, 25 May 2026 16:53:33 GMT</pubDate><lastBuildDate>Mon, 25 May 2026 16:53:33 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@iceslam/launch-nodejs-with-pm2-and-proxying-it-by-apache2</guid><link>https://teletype.in/@iceslam/launch-nodejs-with-pm2-and-proxying-it-by-apache2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/launch-nodejs-with-pm2-and-proxying-it-by-apache2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Разворачиваем NodeJS-проект (NuxtJS) на базе VDS с ОС Ubuntu Server</title><pubDate>Sat, 27 Feb 2021 14:27:02 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/51/85/51857e45-70bb-4435-b94c-703acc61ca6f.png"></media:content><category>Servers</category><description><![CDATA[<img src="https://teletype.in/files/ee/42/ee4235aa-7166-4eb8-9032-371524c9d116.png"></img>Доброго времени суток, уважаемые читатели!]]></description><content:encoded><![CDATA[
  <p>Доброго времени суток, уважаемые читатели!</p>
  <p>В данной статье мы рассмотрим вопрос развертывания с нуля NuxtJS-проекта (либо любого другого проекта на NodeJS) на VDS-сервере с использованием веб-сервера Apahce2, NodeJS, менеджера процессов pm2 с полным циклом установки всех компонентов. </p>
  <p>Установка будет производится на чистом VDS-сервере, не имеющем каких-либо настроек</p>
  <h2>Шаг 1. Подключаемся по SSH к VDS</h2>
  <p>Для подключения к VDS-серверу по SSH более не требуется скачивать и устанавливать какие-либо дополнительные программы, так как в <strong>Windows PowerShell</strong> на ОС Windows 10 последних версий уже встроен клиент OpenSSH.</p>
  <p>Я же буду использовать приложение Windows Terminal, скачать которое можно в Microsoft Store (разработчик <strong>Windows Terminal </strong>- сами Microsoft).</p>
  <p>В данной инструкции в качестве операционной системы на сервере мы будем использовать <strong>Ubuntu Server 20.04</strong></p>
  <p>Итак, подключаемся к серверу при помощи следующей команды</p>
  <pre>ssh root@Ваш_IP_сервера</pre>
  <p>Вместо <strong>root </strong>вы должны указать своего пользователя, который у Вас был выдан при создании сервера.</p>
  <p>Вместо IP-адреса также можно использовать и FQDN-адрес сервера, если вы уже прописали DNS A-запись на Вашем домене со значением Вашего IP-адреса сервера.</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/ee/42/ee4235aa-7166-4eb8-9032-371524c9d116.png" width="786" />
    <figcaption>Команда подключения к серверу по SSH</figcaption>
  </figure>
  <p>При успешном логине Вы увидите уже терминал (консоль) сервера</p>
  <figure class="m_original">
    <img src="https://teletype.in/files/84/4f/844fab14-992d-462e-b1f2-d566ff6b72cb.png" width="680" />
    <figcaption>Терминал Ubuntu Server</figcaption>
  </figure>
  <p>Как видим, мы подключены к удаленному серверу.</p>
  <h2>Шаг 2. Добавление репозитория Apache2 на сервер и установка веб-сервера</h2>
  <p>В данной инструкции мы будем устанавливать веб-сервер Apache2 из официального репозитория, так как в репозитории Ubuntu не всегда последняя версия веб-сервера Apache2.</p>
  <p>Для начала установим необходимые пакеты командой:</p>
  <pre>apt install software-properties-common</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/7a/e9/7ae9f217-dbc5-459a-bc76-9a0d7f1487f8.png" width="578" />
    <figcaption>Команда установки необходимого пакета</figcaption>
  </figure>
  <p>Если данный пакет уже установлен, то вы увидите следующее:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/d0/3e/d03ec480-d5c7-4fc0-ba06-0d61c3efdd0a.png" width="988" />
    <figcaption>Необходимый пакет уже установлен</figcaption>
  </figure>
  <p>После установки необходимых пакетов добавляем официальный репозиторий Apache2 следующей командой:</p>
  <pre>apt-add-repository ppa:ondrej/apache2</pre>
  <p>При добавлении репозитория, в терминале появится вопрос, на который необходимо нажать клавишу <em>Enter</em></p>
  <figure class="m_column">
    <img src="https://teletype.in/files/91/1e/911efdf3-617d-4605-8103-a5de51a9f4d3.png" width="1109" />
    <figcaption>Подтверждение добавления репозитория</figcaption>
  </figure>
  <p>После добавления репозитория производим установку самого веб-сервера Apache2:</p>
  <pre>apt install apache2</pre>
  <p>В терминале появится вопрос о подтверждении установки веб-сервера Apache2. Если согласны с установкой - смело нажимайте клавишу <em>Enter.</em></p>
  <figure class="m_column">
    <img src="https://teletype.in/files/ce/ed/ceedac6d-bfc3-41e4-bd0b-ad6c0559b0f4.png" width="1095" />
    <figcaption>Подтверждение установки пакета Apache2</figcaption>
  </figure>
  <p>Готово!</p>
  <p>Теперь можно перейти по IP-адресу, либо по FQDN-адресу вашего сервера и убедиться, что веб-сервер Apache2 успешно установлен.</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/42/8a/428a6981-a9d8-43f2-ac99-48b79b673cb6.png" width="1368" />
    <figcaption>Успешная установка Apache2</figcaption>
  </figure>
  <h2>Шаг 3. Установка менеджера версий NodeJS (nvm) и самого NodeJS.</h2>
  <p>Для установки и более удобного дальнейшего контроля версий NodeJS мы установки менеджер версии NodeJS. Пакет называется nvm.</p>
  <p>Для этого перейдем в официальный репозиторий на GitHub:</p>
  <p><a href="https://github.com/nvm-sh/nvm" target="_blank">https://github.com/nvm-sh/nvm</a></p>
  <p>И перейдем в раздел Installing and Updating и выберем один их способов установки скрипта. Я выберу второй через утилиту wget:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/1b/8c/1b8c8b44-0a1d-4f47-908d-6493570e8bed.png" width="896" />
    <figcaption>Раздел установки и обновления скрипта NVM в официальном репозитории на GitHub</figcaption>
  </figure>
  <p></p>
  <p>Копируем команду и вставляем ее в терминал сервера:</p>
  <pre>wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/37/5d/375d787a-492d-4782-9732-9f56a9dfe07d.png" width="1028" />
    <figcaption>Команда установки NVM в терминале</figcaption>
  </figure>
  <p>И жмем клавишу <em>Enter</em></p>
  <p>После установки перезагружаем сервер при помощи кнопки перезагрузки в панели управления сервером, либо через команду в терминале<code> init 6 </code></p>
  <figure class="m_column">
    <img src="https://teletype.in/files/1a/e6/1ae6e669-ca1c-43b1-8298-ae2bb7f1b0b6.png" width="762" />
    <figcaption>Автоматическое отключение от сервера после применения команды перезагрузки</figcaption>
  </figure>
  <p>После перезагрузки снова подключаемся к серверу согласно шагу 1.</p>
  <p>Запускаем команду nvm для того, чтобы посмотреть и ознакомится со списком команд скрипта. Находим команду установки NodeJS в версии LTS:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/92/e7/92e70f2f-2414-4b71-ad16-589737a3ebfc.png" width="951" />
    <figcaption>Команда установки NodeJS LTS-версии</figcaption>
  </figure>
  <p>Вводим эту команду в терминал и жмем клавишу <em>Enter</em>:</p>
  <pre>nvm install --lts</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/32/01/32017733-1526-4b58-8ebe-bba7bb1e225b.png" width="1104" />
    <figcaption>Успешная установка NodeJS через менеджер NVM</figcaption>
  </figure>
  <p>Проверяем установленную версию NodeJS слудующей командой:</p>
  <pre>node -v</pre>
  <p>И получаем сообщение об установленной версии NodeJS</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/31/6e/316efed1-a1e0-432e-89d3-b234144b8240.png" width="1104" />
    <figcaption>Установленная версия NodeJS</figcaption>
  </figure>
  <h2>Шаг 4. Установка менеджера процессов pm2</h2>
  <p>Для того, чтобы управлять процессами и приложениями, запущенными в среде NodeJS, а также автоматического их запуска после перезагрузки сервера, нам понадобится менеджер процессов NodeJS, который мы установим глобально в систему через пакетный менеджер npm - pm2:</p>
  <pre>npm install -g pm2</pre>
  <p>При успешной установке мы увидим следующее:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/69/6e/696eae0a-9438-4dfa-8168-6ab2fb59abc4.png" width="1100" />
    <figcaption>Пакет pm2 успешно установлен</figcaption>
  </figure>
  <p>При помощи команды<code> pm2 -h </code>можно посмотреть список доступных команд</p>
  <h2>Шаг 5. Запуск NodeJS-приложения (в нашем случае - NuxtJS-приложения)</h2>
  <p>Я создам новое приложение на NuxtJS для демонстрации работы. Вы же можете запустить таким же образом любое NodeJS-приложение, как новое, только что созданное, так и уже готовое приложение.</p>
  <p>NuxtJS проект по-умолчанию запускается в двух режимах:</p>
  <ul>
    <li>Dev: <code>npm run dev</code></li>
    <li>Prod: <code>npm run build</code> и <code>npm run start</code></li>
  </ul>
  <p>Мы же не будем запускать это приложение этими командами, а сразу воспользуемся менеджером <strong>pm2</strong></p>
  <p>Для этого перейдем в папку с проектом и запустим команду инициализации менеджера <strong>pm2:</strong></p>
  <pre>pm2 init</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/5f/e9/5fe9a3b2-77c0-45b6-b3d5-3569b6f4d9d5.png" width="1108" />
    <figcaption>pm2 сообщает об успешной генерации файла экосистемы</figcaption>
  </figure>
  <p>Открываем файл <code>ecosystem.config.js</code> прямо в терминале через редактор <strong>nano</strong> командой и удаляем все содержимое:</p>
  <pre>nano ecosystem.config.js</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/5f/79/5f79d0c0-3e44-4cf3-9707-27d63f18b416.png" width="1103" />
    <figcaption>Пустой файл ecosystem.config.js с удаленными стандартными значениями</figcaption>
  </figure>
  <p>Вставляем туда следующее содержимое и сохраняем комбинацией клавиш <em>Ctrl+O</em>, затем жмем <em>Enter</em>:</p>
  <pre>module.exports = {
  apps : [
    {
      name: &quot;nuxt-dev&quot;,
      script: &quot;npm&quot;,
      args: &quot;run dev&quot;
    },
    {
      name: &quot;nuxt-prod&quot;,
      script: &quot;npm&quot;,
      args: &quot;run start&quot;
    }
  ]
}</pre>
  <p>Для запуска dev-версии используем команду следующую команду:</p>
  <pre>pm2 start ecosystem.config.js --only nuxt-dev</pre>
  <p>Для запуска prod-версии:</p>
  <pre>npm run build &amp;&amp; pm2 start ecosystem.config.js --only nuxt-prod</pre>
  <p>Я, для примера, запущу Dev-версию</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/8c/36/8c36191c-6214-485b-884a-040135f00fd9.png" width="1271" />
    <figcaption>Запущена dev-версия NuxtJS-приложения через pm2</figcaption>
  </figure>
  <p>Для последующей остановки/запуска приложения не нужно будет заходить в папку с проектом и запускать командой выше. Достаточно будет ввести название приложения из монитора <strong>pm2</strong>:</p>
  <pre>pm2 start nuxt-dev</pre>
  <p>для запуска, либо</p>
  <pre>pm2 stop nuxt-dev </pre>
  <p>для остановки приложения.</p>
  <p>Для просмотра всех запущенных NodeJS-приложений посредством pm2 небходимо ввести в терминал следующую команду:</p>
  <pre>pm2 status</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/05/50/0550c972-8277-4a83-af12-87dac270a51a.png" width="1269" />
    <figcaption>Статус-панель pm2</figcaption>
  </figure>
  <p>Для просмотра монитора процессов:</p>
  <pre>pm2 monit</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/db/75/db7545ef-9981-4932-b0d5-bdad17071415.png" width="1255" />
    <figcaption>Моинтор pm2</figcaption>
  </figure>
  <p>Подключаем автоматический запуск приложений через pm2 после перезагрузки сервера:</p>
  <pre>pm2 startup</pre>
  <p>и сохраняем изменения:</p>
  <pre>pm2 save</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/c7/62/c762a6e1-fe6a-49c7-9015-d1b95c583121.png" width="1278" />
    <figcaption>Запуск автозагрузки и сохранение параметров</figcaption>
  </figure>
  <h3>[Дополнительно] Графический интерфейс pm2 вне терминала</h3>
  <p>Для запуска веб-интерфейса управления процессами pm2 необходимо зарегистрироваться на сайте pm2.io и создать Bucket</p>
  <p>Будем считать, что есть существующий аккаунт и Bucket (инструкцию можно почитать на оф. сайте pm2)</p>
  <p>Вводим команду для подключения к веб-интерфейсу:</p>
  <pre>pm2 plus</pre>
  <p>На первом этапе pm2 спросит, есть ли у Вас аккаунт pm2.io (в нашем случае есть и мы вводим букву <strong><code>y</code></strong> и жмем клавишу <em>Enter</em></p>
  <figure class="m_column">
    <img src="https://teletype.in/files/80/38/8038c4e2-a8cc-47df-8433-66e54c8ec1d9.png" width="999" />
    <figcaption>Есть ли аккаунт pm2.io?</figcaption>
  </figure>
  <p>Вводим ваш email и пароль от аккаунта.</p>
  <p>Если все введено верно, то <strong>pm2</strong> попросит Вас выбрать, к какому Bucket подключиться - выбирайте ранее созданный. У меня это <em>TestBucket</em></p>
  <figure class="m_column">
    <img src="https://teletype.in/files/ff/0f/ff0f1fd0-eaf4-4375-b265-14e4564f8178.png" width="978" />
    <figcaption>Выбор Bucket для подключения приложения к веб-интерфейсу pm2</figcaption>
  </figure>
  <p>При успешном подключении к Bucket в веб-интерфейсе <strong>pm2</strong> появится Ваше приложение(процесс). Там вы сможете посмотреть статистику, сбросить монитор и перезагрузить приложение</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/dd/99/dd99ba8c-170d-4951-b4cc-0cfee334723f.png" width="1920" />
    <figcaption>Веб-интерфейс pm2</figcaption>
  </figure>
  <p>Далее нам необходимо повторно добавить в автозагрузку pm2 и сохранить изменения:</p>
  <pre>pm2 unstartup
pm2 startup
pm2 save</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/ba/f6/baf6cd3d-816f-42b2-92ab-50c0d4f3d663.png" width="983" />
    <figcaption>Перезапуск автозагрузки pm2 и сохранение параметров</figcaption>
  </figure>
  <h2>Шаг 6. Проксирование NodeJS-приложения через Apache2 Proxy</h2>
  <p>У нас уже запущено приложение на NuxtJS на порту 3000 (по-умолчанию)</p>
  <p>Теперь нам необходимо проксировать его на определенный адрес и стандартный порт 80 (для HTTP).</p>
  <p>Для этого установим и включим модуль Apache2 Proxy:</p>
  <pre>a2enmod proxy_http</pre>
  <p>И перезагрузим веб-сервер командой:</p>
  <pre>systemctl restart apache2</pre>
  <figure class="m_column">
    <img src="https://teletype.in/files/ce/fc/cefc356f-285a-4b3c-ad05-21c6954a823b.png" width="986" />
    <figcaption>Включение модуля Apache2 Proxy HTTP</figcaption>
  </figure>
  <p>Переходим в папку с виртуальными хостами Apache2 командой:</p>
  <pre>cd /etc/apache2/sites-available</pre>
  <p>и дублируем дефолтный файл конфигурации виртуального хоста Apache2:</p>
  <pre>cp 000-default.conf ваш_домен.conf</pre>
  <p>Открываем файл ваш_домен.conf с помощью редактора nano. Изменяем на Ваши следующие значения:</p>
  <ul>
    <li><strong>ServerName</strong>: необходимо раскомментировать и значение example.com поменять на ваше доменное имя</li>
    <li><strong>ServerAdmin</strong>: <em>webmaster@localhost</em> меняем на Ваш email</li>
    <li><strong>DocumentRoot</strong>: можно закомментировать значком <strong>#</strong></li>
  </ul>
  <figure class="m_column">
    <img src="https://teletype.in/files/2b/97/2b974a04-2895-413e-be3c-235efb479c29.png" width="973" />
    <figcaption>Пример оформления файла конфигурации виртуального хоста</figcaption>
  </figure>
  <p>Затем, чтобы проксировать наше приложение на этот адрес, нам необходимо добавить следующие строки</p>
  <pre>ProxyPreserveHost On

ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/</pre>
  <p>Где <strong>:3000</strong> - Ваш порт приложения</p>
  <p>Сохраняем изменения комбинацией клавиш <em>Ctrl+O</em> и жмем <em>Enter.</em> Выходим из редактора комбинацией <em>Ctrl+Z</em></p>
  <figure class="m_column">
    <img src="https://teletype.in/files/19/ee/19eed5d6-54d2-4be3-a35c-91971580a107.png" width="983" />
    <figcaption>Проксирование 3000 порта</figcaption>
  </figure>
  <p>Теперь можно включить виртуальный хост и перезагрузить веб-сервер*:</p>
  <pre>a2ensite ваш_домен
systemctl reload apache2</pre>
  <blockquote>* В команде a2ensite ваш_домен не обязательно указывать расширение конфигурационного файла</blockquote>
  <p>Смотрим результат</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/93/3c/933c0566-a652-4dc0-a36a-eaac6a16c4f5.png" width="1919" />
    <figcaption>NuxtJS-приложение успешно проксировано</figcaption>
  </figure>
  <p>Как видим - приложение успешно открывается на необходимом нам адресе и стандартном порту веб-сервера Apache2</p>
  <h2><strong>Шаг 7. Тестирование работы pm2</strong></h2>
  <p>Теперь необходимо проверить, срабатывает ли автоматический запуск приложений менеджером pm2 после перезагрузки сервера.</p>
  <p>Для этого в терминале пропишем команду <code>init 6</code>, либо перезагрузим сервер в панели управления хостингом.</p>
  <p>Если Вы все сделали правильно и согласно инструкции - приложение на NodeJS автоматически запустится на вашем адресе в течение минуты после запуска VDS-сервера.</p>
  <h2>Заключение</h2>
  <p>В данном материале мы рассмотрели подробно установку веб-сервера Apache2, установку менеджера версий NodeJS - NVM и установку самого NodeJS через этот менеджер, запуск NodeJS-приложения на примере приложения на VueJS-фреймворке NuxtJS, автоматический запуск этого приложения после перезагрузки сервера с помощью менеджера процессов pm2 и проксирование приложения на определенный адрес.</p>
  <hr />
  <p>Другие статьи по теме NodeJS приложений, веб-разработки, администрирования серверов Вы можете найти у меня в блоге</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/0WAAVVt1w</guid><link>https://teletype.in/@iceslam/0WAAVVt1w?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/0WAAVVt1w?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Скрипт динамической обложки: инструкция</title><pubDate>Sat, 03 Oct 2020 08:32:42 GMT</pubDate><media:content medium="image" url="https://homework-cool.ru/wp-content/uploads/2017/05/pic-02-PSD-shablon.png"></media:content><category>PHP</category><description><![CDATA[<img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-01-nastrojki-OpenServer-pod-skript-dinamicheskoj-oblozhki.png"></img>Данная инструкция поможет понять, как настроить наш скрипт динамической обложки Вконтакте. Так же вы научитесь настраивать автозапуск скрипта на локальном и удаленном сервере.]]></description><content:encoded><![CDATA[
  <p>Данная инструкция поможет понять, как настроить наш скрипт динамической обложки Вконтакте. Так же вы научитесь настраивать автозапуск скрипта на локальном и удаленном сервере.</p>
  <p>Что такое <a href="https://homework-cool.ru/zarabotok-v-soc-setjah/dinamicheskaya-oblozhka-vkontakte.html" target="_blank">динамическая обложка для группы Вконтакте</a> можно прочитать по ссылке. Там же находится ссылка на скачивание рассматриваемого в статье скрипта.</p>
  <p>После скачивания файлов вы получите <em>скрипт динамической обложки и PSD шаблон</em>, чтобы его редактировать и создать уникальное <a href="https://homework-cool.ru/oformlenie-gruppy-vkontakte" target="_blank">оформление группы Вконтакте</a>.</p>
  <p>Чтобы иметь возможность настраивать скрипт, вам понадобится установить локальный сервер на свой компьютер. Я использую <a href="https://ospanel.io/" target="_blank">OpenServer</a>.</p>
  <p>Перейдите по ссылке и начните скачивать <strong>Premium</strong> или <strong>Ultimate</strong> версию. Бесплатный метод скачивания ограничен в максимальной скорости, так что это может занять какое-то время. А пока вы читаете данную статью, сервер уже наполовину скачается.</p>
  <p>Вы можете использовать любой другой сервер. Это не имеет большого значения. Главное, чтобы в нем был планировщик заданий (cron) и версия PHP не ниже 5.5.</p>
  <blockquote>В некоторых случаях возможны проблемы с запуском OpenServer – его любит блокировать брадмауэр. Если такое происходит, то добавьте программу в исключения и запускайте от имени администратора.</blockquote>
  <p>После успешного запуска сервера (в трее будет гореть зеленый флажок) откройте настройки и в закладке Модули выберите Apache-2.4 и PHP-5.5, как показано на скриншоте.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-01-nastrojki-OpenServer-pod-skript-dinamicheskoj-oblozhki.png" width="582" />
  </figure>
  <p>После сохранения настроек и перезапуска локальный сервер будет полностью готов к работе.</p>
  <h2>Знакомство с PSD шаблоном</h2>
  <p>Откроем и ознакомимся сначала с PSD шаблоном.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-02-PSD-shablon.png" width="1525" />
  </figure>
  <p>Внутри файла все разложено по слоям, любой элемент можно редактировать: менять цвет, размер, форму. Используемый в проекте шрифт есть в папке font со скриптом.</p>
  <p>В общем, изменяйте дизайн по своему усмотрению. Только учтите, что скачанный вами скрипт позволяет отображать следующие элементы:</p>
  <ul>
    <li>Последних подписчиков: от одного до трех;</li>
    <li>Время: в формате 14:59;</li>
    <li>Текущую дату: 21 мая 2017;</li>
    <li>День недели: воскресенье</li>
  </ul>
  <h2>Знакомство с файлами скрипта</h2>
  <p>Переходим в папку со скриптом динамической обложки.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-03-fajly-skripta-dinamicheskoj-oblozhki.png" width="650" />
  </figure>
  <p>В папке cover находится изначальный файл обложки. Он обязательно должен иметь имя cover_bg.jpg. Иначе скрипт не будет работать. Размер файла 1590×400 пикселей.</p>
  <p>В папку font нужно закинуть шрифты, которые вы использовали при разработке дизайна. Настройки шрифта задаются в файле setup.php. Обратите внимание, что названия шрифтов не должны иметь пробелов.</p>
  <p>Файлы function.php, grous_getMembers.php и style.css изменять не рекомендуется. Вы можете их посмотреть, но менять в них ничего не стоит.</p>
  <p>Нужно настраивать только файлы setup.php и при необходимости index.php.</p>
  <h3>Настройка файла setup.php</h3>
  <p>Это основной файл настройки. Открывайте его с помощью текстового редактора. Я рекомендую Notepad++. И в разделе «Типографика» настраиваете используемые шрифты, размер и цвет.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-04-nastrojka-skripta-dinamicheskoj-oblozhki.png" width="690" />
  </figure>
  <p>$font — шрифт отображения имени и фамилии новых подписчиков   $font_clock — шрифт отображения часов   $font_date — шрифт отображения текущей даты и дня недели   $last_subscriber_font_size — размер шрифта имени и фамилии подписчиков   $last_subscriber_font_color — цвет шрифта имени и фамилии подписчиков   $today_font_size — размер шрифта дня недели   $today_font_color — цвет шрифта дня недели   $date_font_size — размер шрифта текущего числа   $date_font_color — цвет шрифта числа   $clock_font_size — размер шрифта часов   $clock_font_color — цвет шрифта часов</p>
  <p>Теперь поднимемся в начало файла. Пора заполнить самую важную часть настройки скрипта.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-05-glavnye-nastrojki.png" width="670" />
  </figure>
  <p>Нам нужно получить токен доступа. Для этого есть отдельный файл token.php. Открываем его:</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-06-poluchenie-tokena.png" width="1220" />
  </figure>
  <p>И видим одну незаполненную ячейку в массиве $params, а именно client_id.</p>
  <p>Чтобы его получить, вам нужно создать свое приложение Вконтакте. Для этого переходим по ссылке: <a href="https://vk.com/apps?act=manage" target="_blank">https://vk.com/apps?act=manage</a></p>
  <ol>
    <li>Жмем в правом верхнем углу кнопку «Создать приложение».</li>
    <li>Придумываем ему название.</li>
    <li>Оставляем платформу Standalone-приложение</li>
    <li>Жмем «Подключить приложение»</li>
    <li>Подтверждаем свои действия с помощью SMS (это бесплатно)</li>
  </ol>
  <p>Все, приложение создано. Просто, правда?</p>
  <p>Переключаем вкладку Настройки и копируем оттуда ID приложения:</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-07-poluchenie-ID-prilozhenija-Vkontakte.png" width="993" />
  </figure>
  <p>После чего вставляем его в файл token.php</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-08-vstavka-ID-v-skript-dinamicheskoj-oblozhki.png" width="530" />
  </figure>
  <p>Жмем сохранить и открываем файл в браузере локального сервера по адресу:</p>
  <p>http://covers-script/token.php</p>
  <blockquote>Этот путь будет верен, если вы не изменяли название папки со скриптом динамической обложки при копировании в проекты OpenServer.</blockquote>
  <p>В браузере сгенерируется ссылка на получение токена. Переходите по ней (откроется в новом окне). Вконтакте попросит разрешить доступ созданному вами приложению к вашему аккаунту. Разрешаете и попадаете на страницу со сгенерированным токеном в адресной строке. Копируете его и вставляете между одинарными кавычками в файле setup.php</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-09-vstavka-tokena-v-skript-dinamicheskoj-oblozhki.png" width="890" />
  </figure>
  <p>$group_id вставляете ID группы, в которую собираетесь устанавливать динамическую обложку.</p>
  <p>Обратите внимание, что получать токен необходимо с аккаунта, которые имеет как минимум права редактора или администратора в сообществе, для которого настраивается динамическая обложка.</p>
  <blockquote>Для настройки обложки можно <a href="https://homework-cool.ru/zarabotok-v-soc-setjah/sozdanie-gruppy-vkontakte.html" target="_blank">создать группу Вконтакте</a> в качестве тестовой и попросить вступить туда 3-5 человек, чтобы скрипту было кого показывать. После завершения всех манипуляций достаточно будет только сменить ID группы и все.</blockquote>
  <p>После того, как эти данные заполнены, можно приступать к следующим настройкам.</p>
  <h4>Настройка отображения новых подписчиков</h4>
  <p>Пролистываем файл setup.php до блока «Последний подписавшийся». В нем можно настроить количество отображаемых подписчиков, размер и форму аватарок: круглые или квадратные. Далее настраивается положение аватарки, имени и фамилии по каждому подписчику.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-10-nastrojka-otobrazhenija-novyh-podpischikov.png" width="670" />
  </figure>
  <p>Координаты расположения аватарки рассчитываются до верхнего левого края. Вычислить их можно с помощью PSD файла. Переключаетесь на нужный слой и тянете направляющую (включаются с помощью Ctrl + R) пока её не примагнитит к краю. Это и будет нужное значение. По оси X значение получилось 816 пикселей. По оси Y высчитывается аналогично.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-11-opredelenie-koordinat-v-PSD-shablone.png" width="900" />
  </figure>
  <p>Координаты расположения текста под аватарками рассчитываются по оси X до центра аватарки, по оси Y до низа текста.</p>
  <p>После того, как пропишите все координаты в соответствии с вашим оформлением <a href="https://homework-cool.ru/zarabotok-v-soc-setjah/oblozhka-dlya-gruppy-vkontakte.html" target="_blank">обложки для группы Вконтакте</a>, можно переходить к завершающим настройкам.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-12-nastrojki-setup.php_.png" width="660" />
  </figure>
  <p>Координаты расположения дня недели (TODAY), даты и часов рассчитываются до левого нижнего угла.</p>
  <p>В блоке «Константа» можно поменять часовой пояс, если он у вас отличается от установленного. Остальное трогать не рекомендуется.</p>
  <h3>Настройка файла index.php</h3>
  <p>На самом деле изменять что-то в этом файле без знаний PHP не следует. Единственное исключение: если нужно изменить выключку текста.</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-13-nastrojki-skripta-indeh.php-dinamicheskoj-oblozhki.png" width="610" />
  </figure>
  <p>Во всех трех случаях выравнивание стоит по левому краю. Если того требует дизайн-макет, вы можете поставить выравнивание по центру или по правому краю. Для этого замените <strong>ALIGN_LEFT</strong> на <strong>ALIGN_CENTER</strong> или <strong>ALIGN_RIGHT</strong> соответственно. Осторожно! Не удалите случайно двоеточие или скобки!</p>
  <blockquote>При изменении выключки имейте ввиду, что тогда для текста координаты по оси X будут рассчитываться до центра объекта или до его правого края.</blockquote>
  <p>На этом настройку можно считать законченной и произвести тестовый запуск скрипта, открыв в браузере ссылку:</p>
  <p>http://covers-script/index.php</p>
  <p>Если все настроено верно, то вы увидите сообщение, что динамическая обложка успешно загружена в группу. А ниже выведется получившееся изображение.</p>
  <h2>Настройка автоматического выполнения скрипта</h2>
  <p>Весь замысел динамической обложки состоит в том, что она обновляется постоянно и без нашего участия. Поэтому нужно научиться работать с планировщиком заданий.</p>
  <h3>Настройка на локальном сервере</h3>
  <p>Первым делом рассмотрим работу с планировщиком OpenServer. Открываем настройки и переключаемся на закладку «Планировщик заданий». В строке «Выполнить» прописываем код:</p>
  <p>%progdir%\modules\wget\bin\wget.exe -q —no-cache http://covers-script/index.php</p>
  <p>Допустим, мы хотим, чтобы скрипт динамической обложки запускался каждые 5 минут. Тогда в верхних ячейках прописываем следующие параметры:</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-14-planirovshhik-zadanij-OpenServer.png" width="650" />
  </figure>
  <p>В первой ячейке */5 расшифровывается как «каждые 5 минут». Если написать */15, то скрипт будет запускаться каждые 15 минут. Если написать просто *, то каждую минуту.</p>
  <p>Нажимаем кнопку сохранить. Сервер перезапустится и cron начнет работать.</p>
  <p>Таким образом можно настроить работу скрипта на компьютере. Но этот вариант не идеален, потому что скрипт будет работать лишь пока компьютер включен.</p>
  <h3>Настройка на хостинге REG.RU</h3>
  <p>Рассмотрим настройку автоматического запуска скрипта динамической обложки на примере <a href="https://homework-cool.ru/kakoj-hosting-vybrat-dlja-sajta" target="_blank">хостинга REG.RU</a>. Алгоритм работы с другими удаленными серверами будет аналогичен. Единственный момент: на разных серверах может отличаться путь до php-интерпретатора. Узнать его можно у службы поддержки или в разделе «Справка», или с помощью команды which php.</p>
  <p>После того, как хостинг будет оплачен и к нему припаркован домен, можно размещать файлы скрипта на удаленном сервере. Для файла index.php обязательно должны быть выставлены права на исполнение: 744 или 755.</p>
  <p>Далее стоит проверить включенную версию PHP. Для этого в ISPmanager находим пункт меню Версия PHP в разделе Инструменты. При необходимости включаем версию 5.5</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-15-versija-PHP-v-ISPmanager.png" width="660" />
  </figure>
  <p>После этого переходим в Планировщик (cron), который находится в том же разделе, и создаем новое задание. В строку «Команда» вводим следующее задание:</p>
  <p>/usr/bin/wget -O /dev/null http://LINK/index.php</p>
  <p>Где <strong>LINK</strong> – это пусть до исполнительного файла скрипта динамической обложки Вконтакте.</p>
  <p>Настраиваете частоту обновлений, выставив нужные значения, и жмете ОК</p>
  <figure class="m_custom">
    <img src="https://homework-cool.ru/wp-content/uploads/2017/05/pic-16-planirovshhik-zadanij-reg.ru_.png" width="530" />
  </figure>
  <p>Задание создано. Подождите некоторое время и убедитесь, что cron работает и обложка обновляется.</p>
  <p>Вот мы и научились запускать скрипт динамической обложки на удаленном сервере. Если у вас что-то не будет получаться, пишите на <a href="mailto:support@homework-cool.ru?subject=Вопрос%20по%20настройке%20скрипта%20динамической%20обложки" target="_blank">нашу почту</a> или в комментариях под статьей.</p>
  <p>Если вам нужен скрипт с дополнительными функциями, также пишите на почту. Мы подберем и реализуем идеальное решение именно для вас.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/l5f1WQHDx</guid><link>https://teletype.in/@iceslam/l5f1WQHDx?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/l5f1WQHDx?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Динамическая обложка для группы ВК, последний подписчик, топ комментатор и прочее</title><pubDate>Sat, 03 Oct 2020 08:31:02 GMT</pubDate><media:content medium="image" url="https://kotoff.net/uploads/posts/2019-03/1553019380_375194-1.jpg"></media:content><category>PHP</category><description><![CDATA[<img src="https://kotoff.net/uploads/posts/2019-03/1553019380_375194-1.jpg"></img>Для установки динамической шапки требуется совсем немного, мы будем использовать компьютер как сервер, в дальнейшем сам скрипт можете установить на купленный сервер или обратиться в нашу группу для установки вашей шапки на ваше сообщество -&gt; В личные сообщения сообщества KotOFF]]></description><content:encoded><![CDATA[
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553019380_375194-1.jpg" width="645" />
  </figure>
  <p>Для установки динамической шапки требуется совсем немного, мы будем использовать компьютер как сервер, в дальнейшем сам скрипт можете установить на купленный сервер или обратиться в нашу группу для установки вашей шапки на ваше сообщество -&gt; <a href="https://vk.me/kotoffs" target="_blank">В личные сообщения сообщества KotOFF</a></p>
  <p>Создание шапки происходит в 4 этапа, о них по порядку </p>
  <p>1. Создание самой шапки.<br />2. Создание скрипта.<br />3. Установка OpenServer.<br />4. Настройка сервера и шапки.</p>
  <h1>1. Создание самой шапки.</h1>
  <p>Шапка должна иметь вот такой вид примерно:</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1552998896_1552998867148.png" width="969" />
  </figure>
  <p>На шапке заранее размещаете будущие отделы для аватарок и имен тех пользователей, который мы будем определять с помощью скрипта </p>
  <p>Для создания такой шапки можно обратиться в группу, которая делает очень дешево такие шапки и оформления для сообществ — &gt; <a href="https://vk.me/totsamyulev" target="_blank">В личные сообщения сообщества Тот самый Лев</a></p>
  <p>На этом с 1 пунктом закончим, переходим к созданию скрипта</p>
  <h1>2. Создание скрипта.</h1>
  <p>Этот процесс самый трудоемкий, поэтому если Вы не хотите вдаваться в подробности, то можете сразу скачать архив и перейти к 3 и 4 пункту настройки.</p>
  <p>Создаем файл с расширением api.php (Скрипт работает на версии php +5.6) и переходим в редактор Sublime Text или любой другой и вставляем туда этот код:</p>
  <pre>&lt;?php

require_once(&#x27;config.php&#x27;);

function DownloadImages($url, $filename){
    $ch = curl_init($url);
    $fp = fopen($filename, &#x27;wb&#x27;);
    curl_setopt($ch, CURLOPT_FILE, $fp);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
}  

function getPOST($url, $post) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url); //урл сайта к которому обращаемся 
    curl_setopt($ch, CURLOPT_HEADER, false); //выводим заголовки
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); //теперь curl вернет нам ответ, а не выведет
    curl_setopt($ch, CURLOPT_POST, true); //передача данных методом POST
    curl_setopt($ch, CURLOPT_USERAGENT,&#x27;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36&#x27;);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post); //тут переменные которые будут переданы методом POST
    $result = curl_exec($ch);
    curl_close($ch);
    
    return $result;
}
    
function getApiMethod($method_name, $params) {
    global $access_token;
    global $api_version;

    // Сделаем проверки на токен и версию апи, если их не указали, добавим.
    if (!array_key_exists(&#x27;access_token&#x27;, $params) &amp;&amp; !is_null($access_token)) {
        $params[&#x27;access_token&#x27;] = $access_token;
    }

    if (!array_key_exists(&#x27;v&#x27;, $params) &amp;&amp; !is_null($api_version)) {
        $params[&#x27;v&#x27;] = $api_version;
    }
    
    // Сортируем массив по ключам
    ksort($params);
    
    // Отправим запрос
    return(getPOST(&#x27;https://api.vk.com/method/&#x27;.$method_name, $params));
}

?&gt;</pre>
  <p>сохраняем и создаем еще 1 файл с названием config.php и вставляем в него следующий код:</p>
  <pre>&lt;?php

// KOTOFF.NET 
// Здесь вводим токен своего ПРОФИЛЯ а не сообщества. Получить можно здесь https://vkhost.github.io/
$access_token = &#x27;ТОКЕН&#x27;;
// ID группы
$group_id = &#x27;ИД ГРУППЫ&#x27;;
// Круглые аватарки [true - круглые false - квадратные]
$roundingOff = true;
// Шрифт текста (положить свой в папку font)
$font = &quot;UniNeue-HeavyItalic.otf&quot;; 

/* ----------------------- ПОСЛЕДНИЙ ПОДПИСАВШИЙСЯ ----------------------- */

// Показывать последнего подписчика [true - показывать false - нет]
$show_last_subscribe = true; 
// Размер шрифта
$last_subscribe_font_size = 20;
// Цвет текста
$last_subscribe_font_color = &#x27;255,255,255&#x27;;
// Ширина аватарки
$last_subscribe_width = 137;
// Высота аватарки
$last_subscribe_height = 137;
// Координаты аватарки по оси Х
$last_subscribe_photo_pixel_x = 44;
// Координаты аватарки по оси Y
$last_subscribe_photo_pixel_y = 66;
// Координаты имени и фамилии по оси Х
$last_subscribe_text_pixel_x = 108;
// Координаты имени и фамилии по оси Y
$last_subscribe_text_pixel_y = 235;


/* ------------------------ ТОП ПО КОЛ-ВУ ЛАЙКОВ ------------------------ */

// Показывать пользователя который за сегодня набрал большее кол-во лайков к комментариям [true - показывать false - нет]
$show_top_like = true; 
// Размер шрифта
$top_like_font_size = 20;
// Цвет текста
$top_like_font_color = &#x27;255,255,255&#x27;;
// Ширина аватарки
$top_like_width = 137;
// Высота аватарки
$top_like_height = 137;
// Координаты аватарки по оси Х
$top_like_photo_pixel_x = 229;
// Координаты аватарки по оси Y
$top_like_photo_pixel_y = 66;
// Координаты имени и фамилии по оси Х
$top_like_text_pixel_x = 295;
// Координаты имени и фамилии по оси Y
$top_like_text_pixel_y = 235;


/* ----------------------- ТОП ПО КОЛ-ВУ КОММЕНТОВ ----------------------- */

// Показывать пользователя который за сегодня оставил большее кол-во комментариев [true - показывать false - нет]
$show_top_comments = true;
// Размер шрифта
$top_comments_font_size = 20;
// Цвет текста
$top_comments_font_color = &#x27;255,255,255&#x27;;
// Ширина аватарки
$top_comments_width = 137;
// Высота аватарки
$top_comments_height = 137;
// Координаты аватарки по оси Х
$top_comments_photo_pixel_x = 416;
// Координаты аватарки по оси Y
$top_comments_photo_pixel_y = 66;
// Координаты имени и фамилии по оси Х
$top_comments_text_pixel_x = 485;
// Координаты имени и фамилии по оси Y
$top_comments_text_pixel_y = 235;

// Домашняя директория скрипта
define(&#x27;BASEPATH&#x27;, str_replace(&#x27;\\&#x27;, &#x27;/&#x27;, dirname(__FILE__)) . &#x27;/&#x27;);
// Временная зона
date_default_timezone_set(&#x27;Europe/Moscow&#x27;);
// Путь к финальному изображению. 
// Минимальный размер обложки 795 x 200
$output_header = BASEPATH.&#x27;header/output.png&#x27;;
// Путь к изображению которое будет браться за основу. 
// Минимальный размер обложки 795 x 200
$image_bg = BASEPATH.&#x27;header/bg.jpg&#x27;;
// Версия API
$api_version = &quot;5.63&quot;;

?&gt;</pre>
  <p>В данном коде нужно указать токен и ID самой группы. Токен должен быть пользовательский<br />Пример:</p>
  <p>$access_token = &#x27;d398d012e185e01edf145450b7899d90b49a6dfee30af063a788deb6a33219249db3463664cd4a0354a57&#x27;;<br />$group_id = &#x27;176771278&#x27;;</p>
  <p>Теперь создаем директорию (папку) с названием header и туда загружаем нашу шапку с таким навзанием — bg.jpg</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1552999851_1552999769510.png" width="490" />
  </figure>
  <p>После этого нужно создать еще 1 папку, где будут хранится наши шрифты для имен пользователей, назовем ее font и загружаем туда наши шрифты, скачать можно ниже</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553001750_1553001682538.png" width="631" />
  </figure>
  <p>Возвращаемся туда, где создавали наши файлы и создаем финальный файл под названием index.php и давайте более детальнее разберем этот код</p>
  <pre>&lt;?php

require_once(&#x27;config.php&#x27;);
require_once(&#x27;api.php&#x27;);

header(&#x27;Content-type: text/html; charset=utf-8&#x27;);

// Получим текущую дату
$date_today = date(&#x27;Ymd&#x27;);

if($show_top_like or $show_top_comments) {
    setLog(&#x27;Получаю посты группы&#x27;);
    // Получим посты со стены
    // больше 100 постов получать нет смысла, так как в вк ограничение
    // разрешено постить не больше 50 постов в сутки.
    $wall_get = getApiMethod(&#x27;wall.get&#x27;, array(
        &#x27;owner_id&#x27; =&gt; &#x27;-&#x27;.$group_id,
        &#x27;count&#x27; =&gt; &#x27;50&#x27;
    ));

    if($wall_get) {
        $wall_get = json_decode($wall_get, true);

        $countlike = array();
        $countcomments = array();
        
        foreach($wall_get[&#x27;response&#x27;][&#x27;items&#x27;] as $wall) {
            
            // Получим кол-во комментариев к посту
            $count = $wall[&#x27;comments&#x27;][&#x27;count&#x27;];
            $offset = 0;

            if($count &gt; 0) { 
                // Получим все комментарии, так как их может быть больше 100.
                while($offset &lt; $count){
                    setLog(&#x27;Получаю кол-во комментариев к посту &#x27;.$wall[&#x27;id&#x27;]);
                    // Отправим запрос на получение комментариев
                    $comments_get = getApiMethod(&#x27;wall.getComments&#x27;, array(
                        &#x27;owner_id&#x27; =&gt; &#x27;-&#x27;.$group_id,
                        &#x27;post_id&#x27; =&gt; $wall[&#x27;id&#x27;],
                        &#x27;need_likes&#x27; =&gt; &#x27;1&#x27;,
                        &#x27;count&#x27; =&gt; &#x27;100&#x27;,
                        &#x27;offset&#x27; =&gt; $offset
                    ));
                    
                    if($comments_get) {
                        $comments_get = json_decode($comments_get, true);

                        foreach($comments_get[&#x27;response&#x27;][&#x27;items&#x27;] as $comments) {
                            
                            if($date_today == date(&#x27;Ymd&#x27;, $comments[&#x27;date&#x27;])) {
                                // В двух словах мы заносим данные в массив, суммируя их
                                if(!isset($countcomments[$comments[&#x27;from_id&#x27;]]) and !isset($countlike[$comments[&#x27;from_id&#x27;]])) {
                                    $countcomments[$comments[&#x27;from_id&#x27;]] = 1;
                                    $countlike[$comments[&#x27;from_id&#x27;]] = $comments[&#x27;likes&#x27;][&#x27;count&#x27;];   
                                } else {
                                    $countcomments[$comments[&#x27;from_id&#x27;]]++;
                                    $countlike[$comments[&#x27;from_id&#x27;]] += $comments[&#x27;likes&#x27;][&#x27;count&#x27;];
                                } 
                                var_dump($comments);
                            }
                            
                        }  
                    }

                    if($offset&lt;$count) 
                        $offset = $offset + 100;
                }
            }

        }
    }
}



if($show_top_like) {
$day_like_top = 0;


if(count($countlike) &gt; 0) {
    // Теперь найдем кто суммарно получил большее кол-во лайков к комментариям
    $value = max($countlike); 
    $day_like_top = array_search($value, $countlike);
    setLog(&#x27;Получаю ID кто сумарно набрал большее кол-во лайков к комментариям &#x27;.$day_like_top);

    if($day_like_top &gt; 0) {
        $user_top_like = getApiMethod(&#x27;users.get&#x27;, array(
            &#x27;user_ids&#x27; =&gt; $day_like_top,
            &#x27;fields&#x27; =&gt; &#x27;photo_200&#x27;
        ));

        if($user_top_like) {
            $user_top_like = json_decode($user_top_like, true);

            $top_like_name = $user_top_like[&#x27;response&#x27;][0][&#x27;first_name&#x27;];
            $top_like_lastname = $user_top_like[&#x27;response&#x27;][0][&#x27;last_name&#x27;];
            $top_like_photo = $user_top_like[&#x27;response&#x27;][0][&#x27;photo_200&#x27;];
            
            // Скачиваем фото
            if(!empty($top_like_name) &amp;&amp; !empty($top_like_lastname) &amp;&amp; !empty($top_like_photo)){
                DownloadImages($top_like_photo, &#x27;header/top_likes.jpg&#x27;);
            }
        }
    }
}

}


if($show_top_comments) {
    $day_comment_top = 0;




if(count($countcomments) &gt; 0) {
        // Теперь найдем кто суммарно написал больше всех комментариев
        $value = max($countcomments); 
        $day_comment_top = array_search($value, $countcomments);
        setLog(&#x27;Получаю ID кто суммарно написал больше всех комментариев &#x27;.$day_comment_top);

        if($day_comment_top &gt; 0) {
            $user_top_comment = getApiMethod(&#x27;users.get&#x27;, array(
                &#x27;user_ids&#x27; =&gt; $day_comment_top,
                &#x27;fields&#x27; =&gt; &#x27;photo_200&#x27;
            ));

            if($user_top_comment) {
                $user_top_comment = json_decode($user_top_comment, true);

                $top_comment_name = $user_top_comment[&#x27;response&#x27;][0][&#x27;first_name&#x27;];
                $top_comment_lastname = $user_top_comment[&#x27;response&#x27;][0][&#x27;last_name&#x27;];
                $top_comment_photo = $user_top_comment[&#x27;response&#x27;][0][&#x27;photo_200&#x27;];
                
                // Скачиваем фото
                if(!empty($top_comment_name) &amp;&amp; !empty($top_comment_lastname) &amp;&amp; !empty($top_comment_photo)){
                    DownloadImages($top_comment_photo, &#x27;header/top_comments.jpg&#x27;);
                }
            }
        }
    }
}


if($show_last_subscribe) {
    // Теперь найдем последнего подписчика
    $last_subscribe = getApiMethod(&#x27;groups.getMembers&#x27;, array(
                &#x27;group_id&#x27; =&gt; $group_id,
                &#x27;sort&#x27; =&gt; &#x27;time_desc&#x27;,
                &#x27;count&#x27; =&gt; &#x27;1&#x27;,
                &#x27;fields&#x27; =&gt; &#x27;photo_200&#x27;,
                &#x27;access_token&#x27; =&gt; $access_token
            ));

    if($last_subscribe) {
        $last_subscribe = json_decode($last_subscribe, true);

        $members_count = $last_subscribe[&#x27;response&#x27;][&#x27;count&#x27;];
        $last_subscribe_firstname = $last_subscribe[&#x27;response&#x27;][&#x27;items&#x27;][0][&#x27;first_name&#x27;];
        $last_subscribe_lastname = $last_subscribe[&#x27;response&#x27;][&#x27;items&#x27;][0][&#x27;last_name&#x27;];
        $last_subscribe_photo = $last_subscribe[&#x27;response&#x27;][&#x27;items&#x27;][0][&#x27;photo_200&#x27;];

        setLog(&#x27;Получаю последнего вступившего в группу &#x27;.$last_subscribe_firstname.&#x27; &#x27;.$last_subscribe_lastname);
        
        // Скачиваем фото
        if(!empty($last_subscribe_firstname) &amp;&amp; !empty($last_subscribe_lastname) &amp;&amp; !empty($last_subscribe_photo)){
            DownloadImages($last_subscribe_photo, &#x27;header/last_subscribe.jpg&#x27;);
        }

    }
}
sleep(3);
if($show_weather){
    $ResultWeatherApi = getPOST(&#x27;http://api.openweathermap.org/data/2.5/weather&#x27;, array(
        &#x27;id&#x27; =&gt; $weather_city_id,
        &#x27;units&#x27; =&gt; &#x27;metric&#x27;,
        &#x27;CNT&#x27; =&gt; &#x27;1&#x27;,
        &#x27;lang&#x27; =&gt; &#x27;ru&#x27;,
        &#x27;appid&#x27; =&gt; $weather_api_id
    ));

    $s = array(
        &#x27;id&#x27; =&gt; $weather_city_id,
        &#x27;units&#x27; =&gt; &#x27;metric&#x27;,
        &#x27;CNT&#x27; =&gt; &#x27;1&#x27;,
        &#x27;lang&#x27; =&gt; &#x27;ru&#x27;,
        &#x27;appid&#x27; =&gt; $weather_api_id
    );
}

// -----------------------------------------------------------------------------
// --------------------------------- РИСОВАНИЕ ---------------------------------
// -----------------------------------------------------------------------------
setLog(&#x27;Создание обложки&#x27;);

$draw = new ImagickDraw(); 
$bg = new Imagick($image_bg);
$draw-&gt;setFont(BASEPATH.&quot;/font/&quot;.$font);
$draw-&gt;setTextAlignment(Imagick::ALIGN_CENTER);

// Последний подписчик
if($show_last_subscribe) {
    $file_name = BASEPATH.&#x27;header/last_subscribe.jpg&#x27;;

    if(file_exists($file_name) &amp;&amp; $show_last_subscribe) {
        $last_subscribe_photo = new Imagick($file_name);
        if($roundingOff==true) {
            RoundingOff($last_subscribe_photo, $last_subscribe_width,$last_subscribe_height);
        }

        $draw-&gt;setFontSize($last_subscribe_font_size);
        $draw-&gt;setFillColor(&quot;rgb(&quot;.$last_subscribe_font_color.&quot;)&quot;);

        $bg-&gt;compositeImage($last_subscribe_photo, Imagick::COMPOSITE_DEFAULT, $last_subscribe_photo_pixel_x, $last_subscribe_photo_pixel_y);
        $bg-&gt;annotateImage($draw, $last_subscribe_text_pixel_x, $last_subscribe_text_pixel_y, 0, mb_strtoupper($last_subscribe_firstname.&quot;\n&quot;.$last_subscribe_lastname, &#x27;UTF-8&#x27;));
    }
}

// Топ по комментам
$file_name = BASEPATH.&#x27;header/top_comments.jpg&#x27;;

if(file_exists($file_name) &amp;&amp; $show_top_comments) {
    $top_comments_photo = new Imagick($file_name);
    if($roundingOff==true) {
        RoundingOff($top_comments_photo, $top_comments_width,$top_comments_height);
    }

    $draw-&gt;setFontSize($top_comments_font_size);
    $draw-&gt;setFillColor(&quot;rgb(&quot;.$top_comments_font_color.&quot;)&quot;);

    $bg-&gt;compositeImage($top_comments_photo, Imagick::COMPOSITE_DEFAULT, $top_comments_photo_pixel_x, $top_comments_photo_pixel_y);
    $bg-&gt;annotateImage($draw, $top_comments_text_pixel_x, $top_comments_text_pixel_y, 0, mb_strtoupper($top_comment_name.&quot;\n&quot;.$top_comment_lastname, &#x27;UTF-8&#x27;));
}

// Топ по лайкам
$file_name = BASEPATH.&#x27;header/top_likes.jpg&#x27;;

if(file_exists($file_name) &amp;&amp; $show_top_like) {
    $top_like_photo = new Imagick($file_name);
    if($roundingOff==true) {
        RoundingOff($top_like_photo, $top_like_width,$top_like_height);
    }

    $draw-&gt;setFontSize($top_like_font_size);
    $draw-&gt;setFillColor(&quot;rgb(&quot;.$top_like_font_color.&quot;)&quot;);

    $bg-&gt;compositeImage($top_like_photo, Imagick::COMPOSITE_DEFAULT, $top_like_photo_pixel_x, $top_like_photo_pixel_y);
    $bg-&gt;annotateImage($draw, $top_like_text_pixel_x, $top_like_text_pixel_y, 0, mb_strtoupper($top_like_name.&quot;\n&quot;.$top_like_lastname, &#x27;UTF-8&#x27;));
}

$bg-&gt;setImageFormat(&quot;png&quot;);
$bg-&gt;writeImage($output_header);

//echo &#x27;&lt;img src=&quot;&#x27;.&#x27;header/output.png&#x27;.&#x27;&quot;&gt;&#x27;;

// -----------------------------------------------------------------------------
// --------------------------- ЗАГРУЗКА НА СЕРВЕР ------------------------------
// -----------------------------------------------------------------------------

// Получим адресс сервера
$getUrl = getApiMethod(&#x27;photos.getOwnerCoverPhotoUploadServer&#x27;, array(
    &#x27;group_id&#x27; =&gt; $group_id,
    &#x27;crop_x2&#x27; =&gt; &#x27;1590&#x27;
));
setLog(&#x27;Получаю адресс сервера &#x27;.$getUrl);


if($getUrl) {
    $getUrl = json_decode($getUrl, true);

    $url = $getUrl[&#x27;response&#x27;][&#x27;upload_url&#x27;];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, array(&#x27;photo&#x27; =&gt; new CURLFile($output_header, &#x27;image/jpeg&#x27;, &#x27;image0&#x27;)));
    $upload = curl_exec( $ch );
    curl_close( $ch );

    if($upload) {
        $upload = json_decode($upload, true);

        $getUrl = getApiMethod(&#x27;photos.saveOwnerCoverPhoto&#x27;, array(
            &#x27;hash&#x27; =&gt; $upload[&#x27;hash&#x27;],
            &#x27;photo&#x27; =&gt; $upload[&#x27;photo&#x27;],
        ));
        
        setLog(&#x27;Загружаю обложку &#x27;.$getUrl);

        if(stripos($getUrl, &#x27;response&quot;:{&quot;images&quot;:[{&#x27;)) {
            print_r(&#x27;Успешно загрузили обложку &lt;a href =&quot;https://kotoff.net/ target=&quot;_blank&quot; &gt;kotoff.net&lt;/a&gt;&lt;/br&gt;&#x27;);
             echo &#x27;&lt;p&gt;*** Больше всех сегодня лайков набрал: &lt;a href =&quot;https://vk.com/id&#x27;.$day_like_top.&#x27;&quot; target=&quot;_blank&quot; &gt;&#x27;.$top_like_name.&#x27; &#x27;.$top_like_lastname.&#x27; - &#x27;.$countlike[$day_like_top].&#x27;&lt;/a&gt; шт.&lt;/p&gt;&lt;/br&gt;&#x27;;
            echo &#x27;&lt;p&gt;*** Больше всех сегодня комментариев написал: &lt;a href =&quot;https://vk.com/id&#x27;.$day_comment_top.&#x27;&quot; target=&quot;_blank&quot; &gt;&#x27;.$top_comment_name.&#x27; &#x27;.$top_comment_lastname.&#x27; - &#x27;.$countcomments[$day_comment_top].&#x27;&lt;/a&gt; шт.&lt;/p&gt;&lt;/br&gt;&#x27;;
              echo &#x27;&lt;p&gt;*** Последний подписчик &lt;a href =&quot;https://vk.com/id&#x27;.$day_like_top.&#x27;&quot; target=&quot;_blank&quot; &gt;&#x27;.$last_subscribe_firstname.&#x27; &#x27;.$last_subscribe_lastname.&#x27;&lt;/a&gt;&lt;/p&gt;&lt;/br&gt;&#x27;;
             echo &#x27;&lt;br&gt;&lt;img src=&quot;&#x27;.&#x27;header/output.png&#x27;.&#x27;&quot;&gt;&#x27;;
            setLog(&#x27;Загружаю обложку в &#x27;.$group_id);
        } else {
            print_r(&#x27;Ошибка при загрузке обложки &#x27;.$getUrl);
            setLog(&#x27;Ошибка при загрузке обложки &#x27;.$getUrl);
        }
        
    }
   
}



function RoundingOff($_imagick, $width, $height) {
    $_imagick-&gt;adaptiveResizeImage($width, $height, 100);
    $_imagick-&gt;setImageFormat(&#x27;png&#x27;);
        
    $_imagick-&gt;roundCornersImage(
        90, 90, 0, 0, 0
    );
}

function setLog($message) {
    $log_file_name = &#x27;logs.txt&#x27;;

    if(file_exists($log_file_name)) {
        $log = array_diff(explode(&quot;\r\n&quot;, file_get_contents($log_file_name)), array(&#x27;&#x27;));
    }

    $log[] = date(&quot;m.d.Y-H:i:s&quot;).&#x27; | &#x27;.$message;

    if(file_put_contents($log_file_name, implode(&quot;\r\n&quot;, $log))) {
        return true;
    } else {
        return false;
    }
}


?&gt;</pre>
  <p>Данный код собирает посты и с помощью циклов считает лайки, комментарии и определяет последнего вступившего. Код полностью рабочий, более детальную настройку рассмотрим в 4 пункте данной статьи. У данного скрипта есть несколько недоработок, часть из них была уже исправлена, для платных групп мы используем собственную версию скрипта. Сохраняем все файлы и переходим к 3 пункту настроек.</p>
  <h1>3. Установка OpenServer.</h1>
  <p>Для работы шапки нам потребуется сервер, а что бы не покупать и не платить деньги, мы будем использовать <strong>Open Server Panel</strong> — это портативная серверная платформа и программная среда для разработки</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553002409_logo.gif" width="360" />
  </figure>
  <p>Переходим на официальный сайт и скачиваем дистрибутив-&gt; <a href="https://kotoff.net/index.php?do=go&url=aHR0cHM6Ly9vc3BhbmVsLmlvL2Rvd25sb2FkLw%3D%3D" target="_blank">Скачать Open Server</a></p>
  <p>Нам предлагают на выбор 3 версии дистрибутива (ULTIMATE PREMIUM BASIC) с различным включенным функционалом, нам подойдет самый простой — BASIC, но если есть возможность, советую скачивать ULTIMATE версию!</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553002703_1553002655563.png" width="853" />
  </figure>
  <p>После скачивания, распаковываем архив в удобное для Вас место, у Вас появится папка OSPanel</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553002919_1553002859322.png" width="1145" />
  </figure>
  <p>Заходим в нее и запускаем наш сервер</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003002_1553002931484.png" width="648" />
  </figure>
  <p>В трее, у Вас появится красный флажок, сервер нужно запустить выбрав зеленый</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003172_1553003081501.png" width="718" />
  </figure>
  <p>После запуска, там же выбираем <u>Папка с сайтами</u> и открываем уже созданный каталог с сайтом localhost, удаляем все что там есть и загружаем наши созданные файлы</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003279_1553003236276.png" width="984" />
  </figure>
  <p>Все готово, переходим к настройке и запуску.</p>
  <h1>4. Настройка сервера и шапки.</h1>
  <p>После успешной настройки, переходим к настройке, перейдя в браузере по адресу — <a href="http://localhost/index.php" target="_blank">http://localhost/index.php</a>:</p>
  <p>Если получили Warning похожий на этот:</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003500_1553003408224.png" width="1036" />
  </figure>
  <p>То Вам нужно проверить правильно ли Вы указали токен профиля или ID группы, получить ID группы можно перейдя настройки сообщества</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003691_1553003667224.png" width="894" />
  </figure>
  <p>Если у Вас стоит короткое название, то просто откройте любую фотографию в группе и скопируйте ID с браузерной строки, все что после photo-ID_ЦИФРЫ (без минуса):</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003847_1553003749425.png" width="613" />
  </figure>
  <p>Если же Вы получили шапку:</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553003559_1553003499512.png" width="1594" />
  </figure>
  <p>Это значит что Вы сделали все правильно, давайте перейдем в группу, напишем пост, комментарий и поставим лайк:</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004161_1553004073253.png" width="902" />
  </figure>
  <p>Снова переходим на — <a href="http://localhost/index.php" target="_blank">http://localhost/index.php</a> и смотрим что у нас получилось:</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004202_1553004195353.png" width="753" />
  </figure>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004236_1553004219307.png" width="884" />
  </figure>
  <p>Как видим все работает, аватарки и текст можно перемещать, так как в Вашей шапке расположение может быть другое как тут например</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004367_1553004345525.png" width="834" />
  </figure>
  <p>Для этого открываем файл config.php</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004464_1553004433607.png" width="1772" />
  </figure>
  <p>И меняем координаты, это один из трудоемких процессов, так как здесь нужно будет поиграться с положением и найти те самые координаты, примерное расположение можно узнавать используя Paint, наводим курсор в верхнюю правую точку устанавливаемого аватара и ниже получаем координаты:</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004700_1553004608911.png" width="518" />
  </figure>
  <p>Это условные координаты по оси Х и Y, далее просто смещаете по несколько пикселей в одну из сторон и находите оптимальную точку.</p>
  <p>Настройка на этом практически завершена. Осталось сделать так, что бы скрипт сам обновлял ее, допустим каждые 5 минут, заходим в настройки OpenServer из трея и выбираем вкладку планировщик задач, прописываем команду:</p>
  <p>%progdir%\modules\wget\bin\wget.exe -q —no-cache http://localhost/index.php</p>
  <p>И указываем тайминги, в какое время нужно запускать скрипт, мы выставили что бы скрипт запускался каждые 5 минут в любой час, день, неделю и месяц, нажимаем добавить и сохраняем, сервер сам перезагрузится и планировщик задач начнет выполнять команду в указанные временные интервалы</p>
  <figure class="m_original">
    <img src="https://kotoff.net/uploads/posts/2019-03/1553004946_1553004849271.png" width="878" />
  </figure>
  <p>При желании, можете загрузить скрипт на хостинг, и использовать CRON для запуска этого скрипта в нужное время.</p>
  <p>На этом у меня все, пишите свои комментарии, задавайте вопросы, мы постараемся ответить на них, всем динамичных шапок</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/easy-generating-ssl-lets-encrypt-on-vps</guid><link>https://teletype.in/@iceslam/easy-generating-ssl-lets-encrypt-on-vps?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/easy-generating-ssl-lets-encrypt-on-vps?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Как повысить безопасность Apache с помощью Let's Encrypt в Ubuntu 18.04</title><pubDate>Wed, 29 Jul 2020 22:28:51 GMT</pubDate><category>Ubuntu</category><description><![CDATA[Let’s Encrypt представляет собой центр сертификации (Certificate Authority, CA), позволяющий получать и устанавливать бесплатные сертификаты TLS/SSL, тем самым позволяя использовать шифрованный HTTPS на веб-серверах. Процесс получения сертификатов упрощается за счёт наличия клиента Certbot, который пытается автоматизировать большую часть (если не все) необходимых операций. В настоящее время весь процесс получения и установки сертификатов полностью автоматизирован и для Apache и для Nginx.]]></description><content:encoded><![CDATA[
  <h3>Введение</h3>
  <p>Let’s Encrypt представляет собой центр сертификации (Certificate Authority, CA), позволяющий получать и устанавливать бесплатные <a href="https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs" target="_blank">сертификаты TLS/SSL</a>, тем самым позволяя использовать шифрованный HTTPS на веб-серверах. Процесс получения сертификатов упрощается за счёт наличия клиента Certbot, который пытается автоматизировать большую часть (если не все) необходимых операций. В настоящее время весь процесс получения и установки сертификатов полностью автоматизирован и для Apache и для Nginx.</p>
  <p>В этом руководстве мы используем Certbot для получения бесплатного SSL сертификата для Apache на Ubuntu 18.04, а также настроим автоматическое продление этого сертификата.</p>
  <p>В этом руководстве мы будем использовать файл отдельного виртуального хоста Apache вместо дефолтного файла конфигурации. <a href="https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-ubuntu-18-04#step-5-%E2%80%94-setting-up-virtual-hosts-recommended" target="_blank">Мы рекомендуем</a> создавать новый файлы виртуальных хостов Apache для каждого доменного имени, потому что это помогает избегать распространённых ошибок и использовать дефолтные файлы в качестве примера корректной конфигурации, когда что-нибудь пойдёт не так.</p>
  <h2>Шаг 1 - Установка Certbot</h2>
  <p>Перед началом использования Let’s Encrypt для получения SSL сертификаты установим Certbot на ваш сервер.</p>
  <p>Certbot находится в активной разработке, поэтому пакеты Certbot, предоставляемые Ubuntu, обычно являются устаревшими. Тем не менее, разработчики Certbot поддерживают свой репозиторий пакетов для Ubuntu с актуальными версиями, поэтому мы будем использовать именно этот репозиторий.</p>
  <p>Сначала добавим репозиторий:</p>
  <pre>sudo add-apt-repository ppa:certbot/certbot
</pre>
  <p>Далее нажмите <code>ENTER</code>.</p>
  <p>Установим пакет Certbot для Apache с помощью <code>apt</code>:</p>
  <pre>sudo apt install python-certbot-apache
</pre>
  <p>Теперь Certbot готов к использованию, но для того, чтобы он мог настроить SSL для Apache, нам сперва необходимо проверить кое-какие настройки Apache.</p>
  <h2>Шаг 2 - Настройка SSL сертификата</h2>
  <p>Certbot должен иметь возможность найти корректный виртуальный хост в вашей конфигурации Apache для того, чтобы автоматически конфигурировать SSL. Для этого он будет искать директиву <code>ServerName</code>, которая совпадает с доменным именем, для которого вы запросите сертификат.</p>
  <p>Если вы следовали инструкциям по <a href="https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-ubuntu-18-04#step-5-%E2%80%94-setting-up-virtual-hosts-recommended" target="_blank">настройке виртуального хоста в руководстве по установке Apache</a>, у вас должен быть виртуальный хост для вашего домена по адресу <code>/etc/apache2/sites-available/example.com.conf</code> с уже правильно настроенной директивой <code>ServerName</code>.</p>
  <p>Для проверки откройте файл серверного блока в <code>nano</code> или любом другом текстовом редакторе:</p>
  <pre>sudo nano /etc/apache2/sites-available/example.com.conf
</pre>
  <p>Найдите строку с <code>ServerName</code>. Она должна выглядеть примерно так:</p>
  <pre>...
ServerName example.com;
...</pre>
  <p>Если она выглядит таким образом, закройте файл и переходите к следующему шагу.</p>
  <p>Если она не выглядит так, как описано выше, обновите директиву <code>ServerName</code>. Затем сохраните и закройте файл, после чего проверьте корректность синтаксиса вашего конфигурационного файла командой:</p>
  <pre>sudo apache2ctl configtest
</pre>
  <p>Если вы получили ошибку, откройте файл серверного блока и проверьте его на наличие опечаток или пропущенных символов. После того, как ваш конфигурационный файл будет проходить проверку на корректность, перезагрузите Apache для применения новой конфигурации:</p>
  <pre>sudo systemctl reload apache2
</pre>
  <p>Теперь Certbot может находить и обновлять корректный виртуальный хост.</p>
  <p>Далее обновим настройки файрвола для пропуска HTTPS трафика.</p>
  <h2>Шаг 3 - Разрешение HTTPS в файрволе</h2>
  <p>Если у вас включен файрвол <code>ufw</code>, как рекомендуется в руководстве по первичной настройке сервера, вам необходимо внести некоторые изменения в его настройки для разрешения трафика HTTPS. К счастью, Apache регистрирует необходимые профили в <code>ufw</code> в момент установки.</p>
  <p>Вы можете ознакомиться с текущими настройками командой:</p>
  <pre>sudo ufw status
</pre>
  <p>Скорее всего вывод будет выглядеть следующим образом:</p>
  <pre>ВыводStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Apache                     ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Apache (v6)                ALLOW       Anywhere (v6)
</pre>
  <p>Как видно из вывода, разрешён только трафик HTTP.</p>
  <p>Для того, чтобы разрешить трафик HTTPS, разрешим профиль <code>Apache Full</code> и удалим избыточный профиль <code>Apache</code>:</p>
  <pre>sudo ufw allow &#x27;Apache Full&#x27;
sudo ufw delete allow &#x27;Apache&#x27;
</pre>
  <p>Проверим внесённые изменения:</p>
  <pre>sudo ufw status
</pre>
  <p>Теперь настройки <code>ufw</code> должны выглядеть следующим образом:</p>
  <pre>ВыводStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Apache Full                ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Apache Full (v6)           ALLOW       Anywhere (v6)  
</pre>
  <p>Теперь мы можем запустить Certbot и получить наши сертификаты.</p>
  <h2>Шаг 4 - Получение SSL сертификата</h2>
  <p>Certbot предоставляет несколько способов получения сертификатов SSL с использованием плагинов. Плагин для Apache берёт на себя настройку Apache и перезагрузку конфигурации, когда это необходимо. Для использования плагина выполним команду:</p>
  <pre>sudo certbot --apache -d example.com -d www.example.com
</pre>
  <p>Эта команда запускает <code>certbot</code> с плагином <code>--apache</code>, ключи <code>-d</code> определяют имена доменов, для которых должен быть выпущен сертификат.</p>
  <p>Если это первый раз, когда вы запускаете <code>certbot</code>, вам будет предложено ввести адрес электронной почты и согласиться с условиями использования сервиса. После этого <code>certbot</code> свяжется с сервером Let’s Encrypt, а затем проверит, что вы действительно контролируете домен, для которого вы запросили сертификат.</p>
  <p>Если всё прошло успешно, <code>certbot</code> спросит, как вы хотите настроить конфигурацию HTTPS.</p>
  <pre>ВыводPlease choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you&#x27;re confident your site works on HTTPS. You can undo this
change by editing your web server&#x27;s configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press &#x27;c&#x27; to cancel):
</pre>
  <p>Выберите подходящий вариант и нажмите <code>ENTER</code>. Конфигурация будет обновлена, а Apache перезапущен для применения изменений. <code>certbot</code> выдаст сообщение о том, что процесс прошёл успешно, и где хранятся ваши сертификаты:</p>
  <pre>ВыводIMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2018-07-23. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the &quot;certonly&quot; option. To non-interactively renew *all* of
   your certificates, run &quot;certbot renew&quot;
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let&#x27;s Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
</pre>
  <p>Ваши сертификаты загружены, установлены и работают. Попробуйте перезагрузить ваш сайт с использованием <code>https://</code> и вы увидите значок безопасности в браузере. Он означает, что соединение с сайтом зашифровано, обычно он выглядит, как зелёная иконка замка. Если вы проверите ваш сервер тестом <a href="https://www.ssllabs.com/ssltest/" target="_blank">SSL Labs Server Test</a>, он получит оценку <strong>A</strong>.</p>
  <p>Закончим тестированием процесса обновления сертификата.</p>
  <h2>Шаг 5 - Проверка автоматического обновления сертификата</h2>
  <p>Сертификаты Let’s Encrypt действительны только 90 дней. Это сделано для того, чтобы пользователи автоматизировали процесс обновления сертификатов. Пакет <code>certbot</code>, который мы установили, делает это путём добавления скрипта обновления в <code>/etc/cron.d</code>. Этот скрипт запускается раз в день и автоматически обновляет любые сертификаты, которые закончатся в течение ближайших 30 дней.</p>
  <p>Для тестирования процесса обновления мы можем сделать “сухой” запуск (dry run) <code>certbot</code>:</p>
  <pre>sudo certbot renew --dry-run
</pre>
  <p>Если вы не видите каких-либо ошибок в результате выполнения этой команды, то всё в полном порядке. При необходимости Certbot будет обновлять ваши сертификаты и перезагружать Apache для применения изменений. Если автоматическое обновление по какой-либо причине закончится ошибкой, Let’s Encrypt отправит электронное письмо на указанный вами адрес электронной почты с информацией о сертификате, который скоро закончится.</p>
  <h2>Заключение</h2>
  <p>В этом руководстве мы рассмотрели процесс установки клиента Let’s Encrypt <code>certbot</code>, загрузили SSL сертификаты для вашего домена, настроили Apache для использования этих сертификатов и настроили процесс автоматического обновления сертификатов. Если у вас есть вопросы по работе с Certbot, рекомендуем ознакомиться с <a href="https://certbot.eff.org/docs/" target="_blank">документацией Certbot</a>.</p>
  <hr />
  <p>Переведено: <a href="https://iceslam.ru" target="_blank">IceSlam</a></p>
  <p>Оригинал: <a href="https://www.digitalocean.com/community/tutorials/apache-let-s-encrypt-ubuntu-18-04-ru" target="_blank">DigitalOcean</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/easy-openvpn-server-installation</guid><link>https://teletype.in/@iceslam/easy-openvpn-server-installation?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/easy-openvpn-server-installation?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Настраиваем OpenVPN-сервер самостоятельно и без лишних хлопот на Ubuntu</title><pubDate>Wed, 29 Jul 2020 21:57:15 GMT</pubDate><category>Servers</category><description><![CDATA[OpenVPN пошаговый автоустановщик для Ubuntu, Debian, CentOS и Fedora.]]></description><content:encoded><![CDATA[
  <p>OpenVPN пошаговый автоустановщик для Ubuntu, Debian, CentOS и Fedora.</p>
  <p>Этот скрипт позволит вам настроить свой собственный VPN-сервер не более чем за минуту, даже если вы раньше не использовали OpenVPN. Он был разработан, чтобы быть как можно более ненавязчивым и универсальным.</p>
  <h3>Установка</h3>
  <p>Запустите скрипт и следуйте за помощником:</p>
  <p><code>wget https://git.io/vpn -O openvpn-install.sh &amp;&amp; bash openvpn-install.sh</code></p>
  <p>Как только он закончится, вы можете запустить его снова, чтобы добавить больше пользователей, удалить некоторых из них или даже полностью удалить OpenVPN.</p>
  <p>Я хочу запустить свой собственный VPN, но у меня нет сервера для этого:</p>
  <p>Недорогие VPS-серверы можно приобрести у компании FirstByte (не реклама), серверы от 55 рублей в месяц</p>
  <hr />
  <p>Переведено: <a href="https://iceslam.ru" target="_blank">IceSlam</a></p>
  <p>Оригинал: <a href="https://github.com/Nyr/openvpn-install" target="_blank">Nyr</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/seo-for-vue-nuxt-project-via-wp-rest-api</guid><link>https://teletype.in/@iceslam/seo-for-vue-nuxt-project-via-wp-rest-api?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/seo-for-vue-nuxt-project-via-wp-rest-api?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>SEO-оптимизация проекта на Vue/Nuxt с использованием WordPress REST API</title><pubDate>Wed, 29 Jul 2020 21:45:11 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/7b/b1/7bb1b800-7ad5-4b48-b4bd-81bad8f81e9d.png"></media:content><category>VueJS</category><description><![CDATA[<img src="https://teletype.in/files/b4/e5/b4e5928b-7653-4126-af39-ebb9c0b45d9f.png"></img>Этот туториал очень просто демонстрирует, как можно было бы использовать Yoast Seo Plugin для WordPress, чтобы получить SEO-заголовок и Meta-данные во фронтенд VueJS/NuxtJS через WordPress REST API.]]></description><content:encoded><![CDATA[
  <h3>WordPress и VueJS/NuxtJS - инструкция по SEO</h3>
  <p>Этот туториал очень просто демонстрирует, как можно было бы использовать Yoast Seo Plugin для WordPress, чтобы получить SEO-заголовок и Meta-данные во фронтенд VueJS/NuxtJS через WordPress REST API.</p>
  <p>В этом пазле несколько кусочков и я постараюсь как можно понятнее, не занимая много времени, объяснить каждый кусочек, в достаточных, не очень трудоемких деталях.</p>
  <p>Я создал простейший пример, чтобы продемонстрировать, как это работает, но вам понадобится гораздо больше, чтобы все это работало гладко в production-версии вашего проекта, про это я кратко коснусь в конце.</p>
  <h2>Мы пройдем через следующие шаги:</h2>
  <ul>
    <li>Установим VueJS (NuxtJS) фронтенда для отображения отдельных постов</li>
    <li>Настроим WordPress API, чтобы получать данные поста через эндпоинт RESTful API</li>
    <li>Добавим Yoast SEO плагин в этот эндпоинт</li>
    <li>Подключим фронтенд VueJS к API чтобы получить данные поста и SEO мета-дату</li>
  </ul>
  <h3>В этом туториале предполагается следующее:</h3>
  <ul>
    <li>Промежуточное знание разработки WordPress (PHP)</li>
    <li>Понимание разработки Javascript и некоторые моменты из того, что с этим связано: NPM и т. д</li>
    <li>Небольшое знакомство с SEO-плагином Yoast для WordPress</li>
    <li>Интерес к использованию VueJS</li>
  </ul>
  <h2>Установим VueJS (NuxtJS) фронтенда для отображения отдельных постов</h2>
  <p>Выберите каталог на вашем компьютере и создайте новый nuxt проект вот так:</p>
  <pre>npx create-nuxt-app &lt;project-name&gt;</pre>
  <p>Следуйте инструкциям и настройте его, как вы хотите — я пошел с NPM без Yarn, без проверки на ошибки, без тестов.</p>
  <p>Выполните следующие действия, чтобы увидеть свой сайт на: <a href="http://localhost:3000" target="_blank">http://localhost:3000</a></p>
  <pre>npm run dev</pre>
  <p>И вуаля - вы увидите, как работает ваш замечательный новый проект!</p>
  <figure class="m_original">
    <img src="https://teletype.in/files/b4/e5/b4e5928b-7653-4126-af39-ebb9c0b45d9f.png" width="700" />
    <figcaption>Страница по умолчанию после установки и запуска проекта на NuxJS</figcaption>
  </figure>
  <p>После этого вам нужно будет перейти в каталог “pages” и создать новую папку под названием “post”. Внутри этой папки создайте два файла: index.vue и _id.vue.</p>
  <p>Индексный файл будет использоваться для отображения страницы списка постов, которые мы не будем рассматривать в этом учебнике, и _id.vue будет использоваться для отображения отдельных постов.</p>
  <p>В &#x27; _id.vue &#x27; теперь добавьте следующий код:</p>
  <pre>&lt;template&gt;
  &lt;section class=&quot;container&quot;&gt;
    &lt;div&gt;
      &lt;logo/&gt;
      &lt;h1 class=&quot;title&quot;&gt;
        Static Post Title
      &lt;/h1&gt;
      &lt;span class=&quot;content&quot;&gt;
        Static Post Content
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/template&gt;
&lt;script&gt;
  export default {}
&lt;/script&gt;
&lt;style&gt;
.container {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}
.title {
  font-family: &#x27;Quicksand&#x27;, &#x27;Source Sans Pro&#x27;, -apple-system, BlinkMacSystemFont,
    &#x27;Segoe UI&#x27;, Roboto, &#x27;Helvetica Neue&#x27;, Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}
&lt;/style&gt;</pre>
  <p>Затем посетите эту страницу: <a href="http://localhost:3000/post/1" target="_blank">http://localhost:3000/post/1</a></p>
  <p>И мы получаем прекрасный маленький шаблон поста, показывающий одни и те же статические данные снова и снова, независимо от того, какой идентификатор вводится в URL-адрес.</p>
  <figure class="m_original">
    <img src="https://teletype.in/files/8d/cd/8dcde90c-8314-4217-83c6-59977f683564.png" width="700" />
    <figcaption>Наша статичная страница поста</figcaption>
  </figure>
  <h2>Далее мы настроим WordPress API, который подгружает данные поста</h2>
  <p>Я устанавливаю WP локально через Docker, но это полностью ваш выбор, как вы хотите выполнить установку. После того, как вы настроили сайт, мы работаем с WordPress Rest API для обслуживания данных поста — с некоторыми дополнительными метаданными SEO с помощью SEO-плагина Yoast.</p>
  <p>WordPress по умолчанию предоставляет конечную точку API для постов.</p>
  <p>Вы можете посетить адрес: <a href="http://localhost/wp-json/wp/v2/posts/POST_ID" target="_blank">http://localhost/wp-json/wp/v2/posts/POST_ID</a></p>
  <p>Мой адрес выглядит так: <a href="http://devapi.seotest.com:20080/wp-json/wp/v2/posts/1" target="_blank">http://devapi.seotest.com:20080/wp-json/wp/v2/posts/1</a></p>
  <p>Это приведет к ответу, который выглядит примерно следующим образом:</p>
  <pre>{  
   &quot;id&quot;:1,
   &quot;date&quot;:&quot;2019-01-03T09:54:21&quot;,
   &quot;date_gmt&quot;:&quot;2019-01-03T09:54:21&quot;,
   &quot;guid&quot;:{  
      &quot;rendered&quot;:&quot;http://devapi.seotest.com:20080/?p=1&quot;
   },
   &quot;modified&quot;:&quot;2019-01-03T09:54:21&quot;,
   &quot;modified_gmt&quot;:&quot;2019-01-03T09:54:21&quot;,
   &quot;slug&quot;:&quot;test-post-seo&quot;,
   &quot;status&quot;:&quot;publish&quot;,
   &quot;type&quot;:&quot;post&quot;,
   &quot;link&quot;:&quot;http://devapi.seotest.com:20080/test-post-seo/&quot;,
   &quot;title&quot;:{  
      &quot;rendered&quot;:&quot;My test Post for SEO&quot;
   },
   &quot;content&quot;:{  
      &quot;rendered&quot;:&quot;&lt;p&gt;My test post main body content &amp;#8211; ain&amp;#8217;t that nice!&lt;/p&gt;\n&quot;,
      &quot;protected&quot;:false
   }........</pre>
  <p>Вот так! У вас есть настройка конечной точки API, которая возвращает данные поста, и вам даже не нужно было писать какой-либо код!</p>
  <h2>Добавим SEO-данные для этих постов</h2>
  <p>Следующая часть также довольно прямолинейна. Нужно добавить seo-метаданные Yoast к этому ответу.</p>
  <p>Перво - наперво - посетите страницу плагинов и установите <a href="https://yoast.com/wordpress/plugins/seo/" target="_blank">плагин Yoast SEO</a></p>
  <p>Я собираюсь сосредоточиться только на названии и мета-описании, чтобы этот пост не стал слишком длинным, но остальные поля следуют очень похожей схеме.</p>
  <p><strong>Добавьте следующий код в свои functions.php:</strong></p>
  <pre>add_action( &#x27;rest_api_init&#x27;, &#x27;slug_register_yoast_seo_meta&#x27; );

function slug_register_yoast_seo_meta() {
    register_rest_field( &#x27;post&#x27;,
        &#x27;_yoast_wpseo_title&#x27;,
        array(
            &#x27;get_callback&#x27;    =&gt; &#x27;get_seo_meta_field&#x27;,
            &#x27;update_callback&#x27; =&gt; null,
            &#x27;schema&#x27;          =&gt; null,
        )
    );
    register_rest_field( &#x27;post&#x27;,
        &#x27;_yoast_wpseo_metadesc&#x27;,
        array(
            &#x27;get_callback&#x27;    =&gt; &#x27;get_seo_meta_field&#x27;,
            &#x27;update_callback&#x27; =&gt; null,
            &#x27;schema&#x27;          =&gt; null,
        )
    );
}

function get_seo_meta_field( $object, $field_name, $request ) {
    return get_post_meta( $object[ &#x27;id&#x27; ], $field_name, true );
}</pre>
  <p><strong>Это приводит к следующему:</strong> </p>
  <p>Хуки в функции &#x27;rest_api_init&#x27; регистрируют два пользовательских поля. Используем &#x27;rest_api_init&#x27; вместо &#x27; init’, чтобы этот код выполнялся только на запросах API, а не на обычных постах...</p>
  <p>Указываем функцию обратного вызова для извлечения двух полей как &#x27; get_seo_meta_field’, которая просто принимает идентификатор объекта (в данном случае post) и имя поля (либо ‘_yoast_wpseo_title’, либо ‘_yoast_wpseo_metadesc’) и возвращает значение этого мета-поля поста.</p>
  <p>Замечательно! Теперь у нас есть конечная точка API для постов, которая возвращает метаданные Yoast SEO!</p>
  <p>Полное описание того, как добавить дополнительные мета-поля в конечные точки, вы можете найти здесь: <a href="https://v2.wp-api.org/extending/modifying" target="_blank">https://v2.wp-api.org/extending/modifying</a></p>
  <h2>Подключите приложение VueJS для извлечения данных поста</h2>
  <p>Это последний шаг — нам нужно сказать фронтенду Vue, чтобы он извлекал данные поста для каждого поста из API WordPress. Мы делаем это следующим образом:</p>
  <p>Мы собираемся использовать Axios для этого, поэтому в вашем _id.vue добавьте следующее в теги &lt;script&gt;.</p>
  <pre>&lt;script&gt;
import axios from &#x27;axios&#x27;export default {
  
  asyncData ({ params }) {
    return axios.get(&#x60;http://devapi.seotest.com:20080/test-post-seo/wp-json/wp/v2/posts/${params.id}&#x60;)
      .then(response =&gt; {
        return { post: response.data }
      })
      .catch((error) =&gt; {
        return { error: error }
      })
  },
  data () {
    return {
      post: {},
      error: []
    }
  }
}
&lt;/script&gt;</pre>
  <p><strong>Что здесь будет происходить?</strong></p>
  <ul>
    <li>Мы импортируем Axios в файл</li>
    <li>Мы используем метод Nuxt ‘asyncData &#x27; для выполнения нашего запроса Axios</li>
    <li>Мы используем параметр динамического идентификатора, чтобы получать разные сообщения, посещая разные URL-адреса</li>
    <li>Мы добавляем возвращаемые POST-данные в объект ‘пост’, что мы создали</li>
  </ul>
  <p><strong>Теперь мы можем отображать динамический заголовок и динамическое содержимое для нашего поста примерно так:</strong></p>
  <pre>&lt;template&gt;
  &lt;section class=&quot;container&quot;&gt;
    &lt;div&gt;
      &lt;h1 class=&quot;title&quot;&gt;
        {{post.title.rendered}}
      &lt;/h1&gt;
      &lt;span v-html=&quot;post.content.rendered&quot;&gt;&lt;/span&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/template&gt;</pre>
  <p><strong>Пожалуйста, обратите внимание на:</strong></p>
  <pre>v-html=”post.content.rendered”</pre>
  <p>Это форматирует HTML разметку возвращенную красиво и мы должны увидеть что-то вроде следующего:</p>
  <figure class="m_original">
    <img src="https://teletype.in/files/50/f6/50f620b7-839a-441f-8dc5-d87b1eb55c40.png" width="700" />
    <figcaption>Ура! Мы получили заголовок!</figcaption>
  </figure>
  <p>Конечно, сам контент будет зависеть от того, что вы помещаете в посте, созданное на стороне WordPress, а идентификатор в строке URL будет зависеть от идентификатора этого поста.</p>
  <p><strong>Далее мы хотим включить SEO данные следующим образом:</strong></p>
  <pre>&lt;script&gt;
import axios from &#x27;axios&#x27;export default {
  head () {
    return {
      title: this.post._yoast_wpseo_title,
      meta: [
        { hid: &#x27;description&#x27;, id: &#x27;description&#x27;, name: &#x27;description&#x27;, content: this.post._yoast_wpseo_metadesc }
      ]
    }
  },
  asyncData ({ params }) {</pre>
  <p><strong>Полный код для файла ниже:</strong></p>
  <pre>&lt;template&gt;
  &lt;section class=&quot;container&quot;&gt;
    &lt;div&gt;
      &lt;h1 class=&quot;title&quot;&gt;
        {{post.title.rendered}}
      &lt;/h1&gt;
      &lt;span v-html=&quot;post.content.rendered&quot;&gt;&lt;/span&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/template&gt;
&lt;script&gt;
import axios from &#x27;axios&#x27;export default {
  head () {
    return {
      title: this.post._yoast_wpseo_title,
      meta: [
        { hid: &#x27;description&#x27;, id: &#x27;description&#x27;, name: &#x27;description&#x27;, content: this.post._yoast_wpseo_metadesc }
      ]
    }
  },
  asyncData ({ params }) {
    return axios.get(&#x60;http://devapi.go2africa.com:20080/wp-json/wp/v2/posts/${params.id}&#x60;)
      .then(response =&gt; {
        return { post: response.data }
      })
      .catch((error) =&gt; {
        return { error: error }
      })
  },
  data () {
    return {
      post: {},
      error: []
    }
  }
}
&lt;/script&gt;
&lt;style&gt;
.container {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}
.title {
  font-family: &#x27;Quicksand&#x27;, &#x27;Source Sans Pro&#x27;, -apple-system, BlinkMacSystemFont,
    &#x27;Segoe UI&#x27;, Roboto, &#x27;Helvetica Neue&#x27;, Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}
.subtitle {
  font-weight: 300;
  font-size: 42px;
  color: #526488;
  word-spacing: 5px;
  padding-bottom: 15px;
}
.links {
  padding-top: 15px;
}
&lt;/style&gt;</pre>
  <p>Это было сделано самым простым из возможных способов - просто чтобы проиллюстрировать, как связать все это вместе. Я упоминаю ниже, как мы на самом деле сделали совсем немного больше, чтобы заставить это работать в production.</p>
  <h2>Заключение</h2>
  <p>Ну вот, теперь у тебя есть Vue.JS фронтенд с SEO, предоставляемым SEO-плагином Yoast из бэкенда WordPress!</p>
  <p><strong>Вот скриншот нашего примера:</strong></p>
  <figure class="m_original">
    <img src="https://teletype.in/files/67/ae/67aeb64e-112d-49a8-ab8b-a993a2c053f6.png" width="700" />
    <figcaption>Вы можете увидеть SEO-заголовок и мета-описание, проходящие через вкладку и консоль!</figcaption>
  </figure>
  <hr />
  <p>Переведено: <a href="https://iceslam.ru" target="_blank">IceSlam</a></p>
  <p>Оригинал: <a href="https://medium.com/nona-web/wordpress-vue-and-nuxt-an-seo-love-story-7593d0827730" target="_blank">NONA-WEB</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/creating-pptp-vpn-server-on-ubuntu-server</guid><link>https://teletype.in/@iceslam/creating-pptp-vpn-server-on-ubuntu-server?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/creating-pptp-vpn-server-on-ubuntu-server?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>PPTP-сервер своими руками на Ubuntu 18.04</title><pubDate>Wed, 29 Jul 2020 15:15:14 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/c3/99/c399f47f-f3b5-44db-83b9-4afa6468efd2.png"></media:content><category>Servers</category><description><![CDATA[<img src="https://profitserver.ru/files/images/faq/vpn-setup/1-ip-forward.jpg?d05f771e2e"></img>Независимо от того, какой из вариантов VPN сервера вы предпочтете, доступ клиентов в Интернет будет реализован штатными средствами операционной системы. Для того, чтобы из внутренней сети открыть доступ в Интернет через внешний интерфейс сервера необходимо разрешить пересылку пакетов между интерфейсами (форвардинг пакетов), и настроить трансляцию адресов.]]></description><content:encoded><![CDATA[
  <h3>Подготовительные операции</h3>
  <p>Независимо от того, какой из вариантов VPN сервера вы предпочтете, доступ клиентов в Интернет будет реализован штатными средствами операционной системы. Для того, чтобы из внутренней сети открыть доступ в Интернет через внешний интерфейс сервера необходимо разрешить пересылку пакетов между интерфейсами (форвардинг пакетов), и настроить трансляцию адресов.</p>
  <p>Для включения форвардинга пакетов откроем файл “/etc/sysctl.conf” и изменим значение параметра “net.ipv4.ip_forward” на 1.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/1-ip-forward.jpg?d05f771e2e" width="773" />
    <figcaption>включение форвардинга пакетов для настройки VPN сервера</figcaption>
  </figure>
  <p>Чтобы изменения применились без перезагрузки сервера, выполним команду</p>
  <p>sudo sysctl -p /etc/sysctl.conf</p>
  <p>Трансляция адресов настраивается средствами iptables. Предварительно уточним имя внешнего сетевого интерфейса, выполнив команду “ip link show”, оно понадобится на следующем шаге. В нашем случае имя интерфейса “ens3”.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/2_ip_link_show.jpg?4a489de69c" width="800" />
    <figcaption>ip link show</figcaption>
  </figure>
  <p>Включаем трансляцию адресов на внешнем интерфейсе для всех узлов локальной сети.</p>
  <p>sudo iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE</p>
  <p>Обратите внимание, что в команде необходимо указать реальное имя сетевого интерфейса. На вашем сервере оно может отличаться.</p>
  <p>По умолчанию все созданные правила iptables сбрасываются после перезагрузки сервера, для того, чтобы этого избежать, воспользуемся утилитой “iptables-persistent” Устанавливаем пакет.</p>
  <p>sudo apt install iptables-persistent</p>
  <p>В процессе установки откроется окно конфигурации, в котором система предложит сохранить текущие правила iptables. Так как правила уже настроены, соглашаемся и дважды нажимаем “Yes”. Теперь, после перезагрузки сервера правила будут восстанавливаться автоматически.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/3_ip_tables_persistent.jpg?9bd8025161" width="800" />
    <figcaption>Включаем трансляцию адресов на внешнем интерфейсе для всех узлов локальной сети</figcaption>
  </figure>
  <h3>1. PPTP сервер</h3>
  <h3>Настройка сервера</h3>
  <p>Устанавливаем пакет</p>
  <p>sudo apt install pptpd</p>
  <p>После завершения установки открываем в любом текстовом редакторе файл “/etc/pptpd.conf” и приводим его к следующему виду.</p>
  <p><code>option /etc/ppp/pptpd-options #путь к файлу с настройками</code></p>
  <p><code> logwtmp #механизм логирования клиентских подключений</code></p>
  <p><code> connections 100 #количество одновременных подключений</code></p>
  <p><code> localip 172.16.0.1 #адрес, который будет шлюзом для клиентов</code></p>
  <p>remoteip 172.16.0.2-200 #диапазон адресов для клиентов</p>
  <p>Далее редактируем файл “/etc/ppp/pptpd-options”, большинство параметров уже установлены по умолчанию.</p>
  <p><code>#имя сервиса, потребуется при создании учетных записей для клиентов</code></p>
  <p>name pptpd</p>
  <p><code>#запрещаем устаревшие методы аутентификации</code></p>
  <p><code> refuse-pap</code></p>
  <p><code> refuse-chap</code></p>
  <p>refuse-mschap</p>
  <p><code>#разрешаем более надежный метод аутентификации</code></p>
  <p>require-mschap-v2</p>
  <p><code>#включаем шифрование</code></p>
  <p>require-mppe-128</p>
  <p><code>#указываем dns сервера для клиентов, можно указать любые доступные</code></p>
  <p><code> ms-dns 8.8.8.8</code></p>
  <p>ms-dns 8.8.4.4</p>
  <p><code>proxyarp</code></p>
  <p><code> nodefaultroute</code></p>
  <p><code> lock</code></p>
  <p><code> nobsdcomp</code></p>
  <p><code> novj</code></p>
  <p><code> novjccomp</code></p>
  <p>nologfd</p>
  <p>На следующем этапе необходимо создать учетную запись для подключения клиентов. Предположим, мы хотим добавить пользователя “vpnuser”, с паролем “1” и разрешить для него динамическую адресацию. Открываем файл “/etc/ppp/chap-secrets” и добавляем в конец строку с параметрами пользователя.</p>
  <p>vpnuser pptpd 1 *</p>
  <p>Значение “pptpd” это имя сервиса, которое мы указали в файле “pptpd-options”. Вместо символа “*” для каждого клиента можно указать фиксированный ip-адрес. В результате содержимое файла “chap-secrets” будет таким.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/4_chap_secreets.jpg?3e479666af" width="701" />
    <figcaption>Настройка VPN сервера - создание учетной записи для подключения клиентов</figcaption>
  </figure>
  <p>Для применения настроек перезагружаем службу pptpd и добавляем её в автозагрузку.</p>
  <p><code>sudo systemctl restart pptpd</code></p>
  <p>sudo systemctl enable pptpd</p>
  <p>Настройка сервера завершена.</p>
  <h3>Настройка клиента</h3>
  <p>Открываем “Пуск” - “Параметры” - “Сеть и интернет” - “VPN” и нажимаем “Добавить VPN-подключение”</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/5_VPN_add.jpg?3429c064d4" width="497" />
    <figcaption>Настройка клиента для VPN подключения</figcaption>
  </figure>
  <p>В открывшемся окне вводим параметры подключения и нажимаем “Сохранить”</p>
  <ul>
    <li>Поставщик услуг VPN: “Windows (встроенные)”</li>
    <li>Имя подключения: “vpn_connect” (можно ввести любое)</li>
    <li>Имя или адрес сервера: (указываем внешний ip адрес сервера)</li>
    <li>Тип VPN: “Автоматически”</li>
    <li>Тип данных для входа: “Имя пользователя и пароль”</li>
    <li>Имя пользователя: vpnuser (имя, которое указано в файле “chap-secrets” на сервере)</li>
    <li>Пароль: 1 (так же из файла “chap-secrets”)</li>
  </ul>
  <p>После сохранения параметров, в окне VPN появится новое подключение. Щелкаем по нему левой кнопкой мыши и нажимаем “Подключиться”. При успешном соединении с сервером, на значке подключения появится надпись “Подключено”.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/6_vpn_connect.jpg?1d6d856507" width="556" />
    <figcaption>Добавляем VPN подключение</figcaption>
  </figure>
  <p>В свойствах подключения отображаются внутренние адреса клиента и сервера. В поле “Адрес назначения” указан внешний адрес сервера.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/7_vpn_connect_prop.jpg?5e54a17075" width="612" />
    <figcaption>В свойствах подключения отображаются внутренние адреса клиента и сервера. В поле “Адрес назначения” указан внешний адрес сервера.</figcaption>
  </figure>
  <p>При установленном соединении внутренний ip-адрес сервера, в нашем случае 172.16.0.1, становится шлюзом по умолчанию для всех исходящих пакетов.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vpn-setup/8_test_connect.jpg?daaea6d349" width="635" />
    <figcaption>Проверка внешнего адреса компьютера при настройке VPN-соединения</figcaption>
  </figure>
  <h4>Воспользовавшись любым онлайн-сервисом вы можете убедиться, что внешний IP адрес компьютера теперь совпадает с IP адресом вашего VPN сервера.</h4>
  <hr />
  <p>Материал с сайта <a href="https://profitserver.ru/knowledge-base/vpn-setup-linux" target="_blank">profitserver.ru</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/how-to-install-lamp-on-ubuntu-server</guid><link>https://teletype.in/@iceslam/how-to-install-lamp-on-ubuntu-server?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/how-to-install-lamp-on-ubuntu-server?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Настройка веб-сервера (Apache-PHP-MySQL/MariaDB) на Linux Ubuntu</title><pubDate>Wed, 29 Jul 2020 15:13:52 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/84/f9/84f9b3a2-750a-4771-912c-d44fb0045e28.png"></media:content><category>Servers</category><description><![CDATA[<img src="https://profitserver.ru/files/images/faq/vps-web-server/1-apache-default-page.jpg?491d621b81"></img>В данной статье будет дана пошаговая инструкция, как настроить веб-окружение на сервере под управлением Linux. Для начала, необходимо понимать, что типовой веб сервер состоит из взаимодействующих между собой компонентов, а именно:]]></description><content:encoded><![CDATA[
  <p>В данной статье будет дана пошаговая инструкция, как настроить веб-окружение на сервере под управлением Linux. Для начала, необходимо понимать, что типовой веб сервер состоит из взаимодействующих между собой компонентов, а именно:</p>
  <ul>
    <li>HTTP сервер</li>
    <li>интерпретатор языка программирования</li>
    <li>система управления базами данных (СУБД)</li>
  </ul>
  <p>Также для работы с сайтом необходима система управления контентом (CMS), веб интерфейс для управления базами данных и возможность доступа по FTP.</p>
  <p>Рассмотрим процесс установки и настройки распространенной связки Apache-PHP-MySQL(MariaDB) в операционной системе Linux. Дополнительно будут установлены ftp-сервер vsftpd, веб-интерфейс для управления базой данных phpMyAdmin и система управления контентом Wordpress.</p>
  <p>Для начала работы, следует <a href="https://profitserver.ru/vps/" target="_blank">заказать VPS</a> или <a href="https://profitserver.ru/dedicated/" target="_blank">выделенный сервер</a>. В данной статье примеры выполнены на виртуальном сервере со статическим публичным IP-адресом под управлением Ubuntu Server 18.04. Команды выполняются от имени суперпользователя.</p>
  <h3>Настройка HTTP-сервера Apache</h3>
  <h3>1. Установка</h3>
  <p><code>apt install apache2</code></p>
  <p>После завершения установки откроем браузер на любом устройстве с доступом в Интернет и перейдем по ссылке <strong>“http://[ip_адрес_сервера]”</strong></p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/1-apache-default-page.jpg?491d621b81" width="800" />
    <figcaption>Установка и настрйока HTTP-сервера</figcaption>
  </figure>
  <p>Если вы увидите страницу приветствия как на скриншоте, значит HTTP сервер работает.</p>
  <h3>2. Создание тестовой страницы</h3>
  <p>По умолчанию корневым каталогом для размещения сайта является директория <strong>“/var/www/html”</strong>, именно там находится страница приветствия. Создадим отдельную директорию <strong>“/var/www/sites”</strong> для размещения виртуальных хостов и вложенную папку <strong>“/var/www/sites/site1”</strong> с индексной страницей тестового сайта.</p>
  <p><code>cd /var/www/</code></p>
  <p><code>mkdir -p sites/site1</code></p>
  <p><code>echo &quot;&lt;H1&gt;Welcome&lt;/H1&gt;&quot; &gt; sites/site1/index.html</code></p>
  <p>В результате файл <strong>“/var/www/sites/site1/index.html”</strong> будет содержать одну html-строку:</p>
  <p><code>&lt;H1&gt;Welcome&lt;/H1&gt;</code></p>
  <h3>3. Конфигурация Apache-сервера</h3>
  <p>Конфигурационные файлы сайтов находятся в каталоге <strong>“/etc/apache2/sites-available/”</strong>. Создадим конфигурационный файл для нового виртуального хоста взяв за основу конфигурацию по умолчанию из файла <strong>“000-default.conf”</strong></p>
  <p><code>cd /etc/apache2/sites-available/</code></p>
  <p><code>cp 000-default.conf site1.conf</code></p>
  <p>Откроем файл <strong>“site1.conf”</strong> и изменим параметр <strong>“DocumentRoot”</strong>. В качестве значения нужно указать путь к новому сайту, в нашем случае это <strong>“/var/www/sites/site1”</strong></p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/2-new-conf.jpg" width="800" />
    <figcaption>Настрйока и конфигурация Apache-сервера</figcaption>
  </figure>
  <p>На данном этапе нам не требуется настройка одновременной работы нескольких сайтов, поэтому отключим сайт по умолчанию и включим новый сайт. Для применения изменений перезагружаем конфигурацию сервера.</p>
  <p><code>a2dissite 000-default</code></p>
  <p><code>a2ensite site1</code></p>
  <p><code>systemctl reload apache2</code></p>
  <p>Снова переходим по ссылке <strong>“http://[ip_адрес_сервера]”</strong> и убеждаемся, что вместо стандартной страницы приветствия отображается наша новая страница.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/3-new-site.jpg" width="663" />
    <figcaption>Настройка HTTP-сервера</figcaption>
  </figure>
  <p>Настройка HTTP-сервера завершена, переходим к следующему этапу.</p>
  <h3>Настройка FTP-сервера</h3>
  <h3>1. Установка</h3>
  <p>Устанавливаем ftp-сервер и дополнительный пакет <strong>“db-util”</strong>, который потребуется для настройки виртуальных пользователей.</p>
  <p><code>apt install vsftpd db-util</code></p>
  <h3>2. Создание локальной учетной записи</h3>
  <p>Сервер <strong>vsftpd</strong> позволяет очень гибко настраивать права доступа. Для решения наших задач ftp-пользователям необходимо обеспечить следующие возможности:</p>
  <ul>
    <li>полный доступ к содержимому директории <strong>“/var/www/sites/”</strong>;</li>
    <li>невозможность выхода за пределы директории <strong>“/var/www/”</strong>;</li>
    <li>подключение с использованием виртуальной учетной записи;</li>
  </ul>
  <p>Создадим локальную учетную запись <strong>“virtual”</strong> без возможности входа в систему, с домашней директорией <strong>“/var/www/”</strong>. Эта учетная запись будет использоваться для подключения виртуальных ftp-пользователей.</p>
  <p><code>useradd -d /var/www virtual</code></p>
  <p>По умолчанию, владельцем директории <strong>“/var/www”</strong> является <strong>“root”</strong>. Для того, того, чтобы ftp-пользователи могли изменять содержимое сайтов, изменим владельца каталога <strong>“/var/www/sites/”</strong>, включая вложенные папки на <strong>“virtual”</strong>.</p>
  <p><code>chown -R virtual:root /var/www/sites</code></p>
  <p>В результате изменения прав, пользователь <strong>“virtual”</strong> сможет просматривать содержимое каталога <strong>“/var/www/”</strong> и записывать во вложенный каталог <strong>“/var/www/sites/”</strong></p>
  <h3>3. Конфигурация</h3>
  <p>Основная конфигурация хранится в файле <strong>“/etc/vsftpd.conf”</strong>, приводим его к следующему виду:</p>
  <p><code>#Включаем виртуальных пользователей</code></p>
  <p><code>anonymous_enable=NO</code></p>
  <p><code>local_enable=YES</code></p>
  <p><code>guest_enable=YES</code></p>
  <p><code>guest_username=virtual</code></p>
  <p><code>#Настраиваем права</code></p>
  <p><code>write_enable=YES</code></p>
  <p><code>anon_upload_enable=YES</code></p>
  <p><code>anon_mkdir_write_enable=YES</code></p>
  <p><code>anon_other_write_enable=YES</code></p>
  <p><code>anon_world_readable_only=NO</code></p>
  <p><code>anon_umask=0022</code></p>
  <p><code>chroot_local_user=YES</code></p>
  <p><code>#задаем параметры запуска</code></p>
  <p><code>listen=YES</code></p>
  <p><code>pasv_min_port=30000</code></p>
  <p><code>pasv_max_port=30999</code></p>
  <h3>4. Создание базы данных</h3>
  <p>База данных необходима для хранения виртуальных учетных записей.</p>
  <p>Предварительно создадим в домашнем каталоге простой текстовый файл <strong>“users.txt”</strong> и запишем логины и пароли виртуальных пользователей в чередующиеся строки. Например нам нужен виртуальный пользователь с логином <strong>“ftp”</strong> и паролем <strong>“Qwe123”</strong>, тогда содержимое файла будет таким:</p>
  <p><code>ftp</code></p>
  <p><code>Qwe123</code></p>
  <p>Создаем базу данных</p>
  <p><code>db_load -T -t hash -f ~/users.txt /etc/vsftpd_login.db</code></p>
  <p>Меняем стандартное содержимое PAM файла <strong>“/etc/pam.d/vsftpd”</strong> на следующие строки.</p>
  <p><code>auth required /lib/x86_64-linux-gnu/security/pam_userdb.so db=/etc/vsftpd_login</code></p>
  <p><code>account required /lib/x86_64-linux-gnu/security/pam_userdb.so db=/etc/vsftpd_login</code></p>
  <p>Обратите внимание, что в различных дистрибутивах расположение библиотеки <strong>“pam_userdb.so”</strong> может отличаться, при необходимости путь к файлу нужно скорректировать.</p>
  <p>Для применения изменений перезагружаем <strong>vsftpd</strong> сервер.</p>
  <p><code>systemctl restart vsftpd</code></p>
  <p>Настройка FTP-сервера завершена.</p>
  <p>Данные для подключения:</p>
  <ul>
    <li>ftp://[ip_адрес_сервера]</li>
    <li>Логин: ftp</li>
    <li>Пароль: Qwe123</li>
  </ul>
  <h3>Настройка PHP-сервера</h3>
  <h3>1. Установка</h3>
  <p>На текущий момент последней стабильной версией PHP является <strong>php 7.4.5</strong>, которая отсутствует в официальных репозиториях Ubuntu. Подключим сторонний репозиторий и установим последнюю версию PHP.</p>
  <p><code>apt update</code></p>
  <p><code>apt install software-properties-common</code></p>
  <p><code>add-apt-repository ppa:ondrej/php</code></p>
  <p><code>apt update</code></p>
  <p><code>apt install php7.4</code></p>
  <h3>2. Проверка</h3>
  <p>Для того, чтобы PHP код мог быть исполнен, файл веб страницы должен иметь расширение <strong>“.php”</strong>. Переименовываем тестовою страницу</p>
  <p><code>cd /var/www/sites/site1/</code></p>
  <p><code>mv index.html index.php</code></p>
  <p>Добавляем в файл <strong>“/var/www/sites/site1/index.php”</strong> строку php-кода. В результате содержимое файла будет таким:</p>
  <p><code>&lt;H1&gt;Welcome&lt;/H1&gt;</code></p>
  <p><code> &lt;?php</code></p>
  <p><code> phpinfo();</code></p>
  <p><code> ?&gt;</code></p>
  <p>Сохраняем изменения и проверяем результат в браузере.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/4-test-php.jpg" width="800" />
    <figcaption>Настройка PHP-сервера</figcaption>
  </figure>
  <p>Если вы видите результат работы функции <strong>“phpinfo()”</strong>, значит интерпретатор PHP работает корректно. Приступаем к следующему этапу.</p>
  <h3>Настройка MySQL (MariaDB)</h3>
  <h3>1. Установка</h3>
  <p>Устанавливаем MariaDB и PHP-модуль для работы с MySQL, после завершения установки перезагружаем Apache</p>
  <p><code>apt install mariadb-server php-mysql</code></p>
  <p><code>systemctl restart apache2</code></p>
  <p>Для проверки обновим тестовую страницу и в таблице с конфигурацией PHP и перейдем к разделу <strong>PDO</strong>. Наличие секции <strong>“PDO_mysql”</strong> говорит о корректной установке драйвера для работой с базой данных Mysql.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/5-pdo-mysql.jpg" width="800" />
    <figcaption>Настройка и установка MySQL на сервер</figcaption>
  </figure>
  <p>Для дальнейшей работы необходимо выполнить первоначальную настройку безопасности MariaDB, во время которой для пользователя<strong> “root”</strong> устанавливается пароль, запрещается удаленный вход и удаляются гостевые учетные записи.</p>
  <p><code>mysql_secure_installation</code></p>
  <p>На первом шаге необходимо ввести пароль пользователя<strong> &quot;root&quot;</strong> для входа в СУБД или нажать Enter, если пароль не задан. Так как после установки учетная запись <strong>&quot;root&quot;</strong> не имеет пароля, нажимаем<strong> “Enter”</strong>.</p>
  <p>Обратите внимание, что в MariaDB существуют собственные учетные записи, которые не имеют отношения к учетным записям операционной системы. Речь идет о пользователе <strong>&quot;root&quot;</strong> в MariaDB.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/6-mysql-secure-inst.jpg" width="800" />
    <figcaption>MySQL: Создание пользователя и установка пароля</figcaption>
  </figure>
  <p>Далее конфигуратор предложит задать пароль для пользователя <strong>root</strong>, нажимаем<strong> “y”</strong> для подтверждения и вводим новый пароль, в нашем случае <strong>“Qwe123”</strong></p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/7-mysql-secure-pass.jpg" width="800" />
    <figcaption>MySQL: установка пароля и доступа пользователей</figcaption>
  </figure>
  <p>На все последующие запросы просто нажимаем <strong>“y”</strong> до окончания настройки.</p>
  <p>Настройка завершена.</p>
  <p><strong>Данные для входа в MariaDB:</strong></p>
  <ul>
    <li>Логин: root</li>
    <li>Пароль: Qwe123</li>
  </ul>
  <h3>Настройка phpMyAdmin</h3>
  <h3>1. Установка</h3>
  <p>Устанавливаем обязательное PHP-расширение <strong>mbstring</strong>.</p>
  <p><code>apt install php-mbstring</code></p>
  <p>В официальном репозитории размещена устаревшая версия phpMyAdmin, поэтому выполним установку в ручном режиме.</p>
  <p>Заходим на официальный сайт проекта “<a href="https://www.phpmyadmin.net/" target="_blank">https://www.phpmyadmin.net/</a>” и скачиваем архив актуальной версии.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/8-pma-download.jpg" width="800" />
    <figcaption>Установка phpMyAdmin на сервер под управлением Linux</figcaption>
  </figure>
  <p>Копируем архив на сервер в каталог <strong>“/var/www/sites/”</strong> используя любой ftp-клиент.</p>
  <p>Распаковываем архив, и для удобства, переименовываем извлеченную папку в <strong>“phpMyAdmin”</strong>. Для распаковки zip-архива предварительно установим утилиту <strong>“unzip”</strong>. После распаковки архив можно удалить.</p>
  <p><code>apt install unzip</code></p>
  <p><code>cd /var/www/sites/</code></p>
  <p><code>unzip phpMyAdmin-5.0.2-all-languages.zip</code></p>
  <p><code>mv phpMyAdmin-5.0.2-all-languages phpMyAdmin</code></p>
  <p><code>rm phpMyAdmin-5.0.2-all-languages.zip</code></p>
  <p>Создаем папку <strong>“/var/www/sites/phpMyAdmin/tmp”</strong> для хранения временных файлов с полными доступом для всех. Если этого не сделать phpMyAdmin сообщит об отсутствии доступа в временной папке.</p>
  <p><code>cd /var/www/sites/phpMyAdmin/</code></p>
  <p><code>mkdir tmp</code></p>
  <p><code>chmod 777 tmp</code></p>
  <h3>2. Создание псевдонима</h3>
  <p>Так как phpMyAdmin не является отдельным виртуальным хостом и находится за пределами корневой директории сайта, настроим псевдоним для возможности доступа.</p>
  <p>Открываем файл <strong>“/etc/apache2/mods-available/alias.conf”</strong> и вставляем строку</p>
  <p><code>Alias /pma “/var/www/sites/phpMyAdmin&quot;</code></p>
  <p>внутри секции</p>
  <p><code>&lt;IfModule alias_module&gt;</code></p>
  <p><code> &lt;/IfModule&gt;</code></p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/9-pma-alias.jpg" width="797" />
    <figcaption>Создание псевдонима в phpMyAdmin</figcaption>
  </figure>
  <p>Перезагружаем конфигурацию Apache для применения изменений.</p>
  <p><code>systemctl reload apache2</code></p>
  <p>Псевдоним настроен. Сейчас мы можем входить в phpMyAdmin по ссылке <strong>“http://[ip_адрес_сервера]/pma”</strong></p>
  <h3>3. Подготовка базы данных</h3>
  <p>Так как при первоначальной настройке MariaDB мы запретили использование учетной записи <strong>root</strong> для удаленного подключения, необходимо создать новую учетную запись с полными правами, которая будет использоваться для входа в phpMyAdmin.</p>
  <p>Кроме того, для работы дополнительных функций phpMyAdmin необходима служебная база данных и учетная запись для доступа к ней.</p>
  <p>Создадим учетные записи</p>
  <p><code>mariadb -u root -p</code></p>
  <p><code>GRANT ALL PRIVILEGES ON *.* TO &#x27;pma&#x27;@&#x27;localhost&#x27; IDENTIFIED BY &#x27;Qwe123&#x27; WITH GRANT OPTION;</code></p>
  <p><code>GRANT SELECT, INSERT, UPDATE, DELETE ON &#x60;phpmyadmin&#x60;.* TO &#x27;pmaservice&#x27;@&#x27;localhost&#x27; IDENTIFIED BY &#x27;Qwe123&#x27; WITH grant option;</code></p>
  <p><code>quit</code></p>
  <p><u>Обратите внимание, что имя базы данных во втором запросе заключено в обратные апострофы: “… ON <strong>&#x60;phpmyadmin&#x60;</strong>.* TO &#x27;pma&#x27;@&#x27;localhost&#x27; IDENTIFIED BY …”,</u></p>
  <p>В результате в MariaDB будет создано две учетные записи:</p>
  <ol>
    <li>Логин: pma, пароль: Qwe123</li>
    <li>Учетная запись имеет полные права и будет использоваться для входа в phpMyAdmin</li>
    <li>Логин: pmaservice, пароль:Qwe123</li>
    <li>Служебная учетная запись необходимая для работы дополнительных функций.</li>
  </ol>
  <p><u>На следующем шаге эти учетные данные должны быть указаны в конфигурационном файле <strong>“config.inc.php”</strong></u></p>
  <p>Далее необходимо импортировать базу данных из файла <strong>“phpMyAdmin/sql/create_tables.sql”</strong>. Выполним импорт средствами phpMyAdmin.</p>
  <p>Открываем браузер и переходим по ссылке <strong>“http://[ip_адрес _сервера]/pma”</strong></p>
  <p>Вводим логин <strong>“pma”</strong>, пароль <strong>“Qwe123”</strong></p>
  <p>Переходим на вкладку <strong>“Импорт”</strong>, нажимаем кнопку <strong>“Выберите файл”</strong> и выбираем файл <strong>”sql/create_tables.sql”</strong> в корневой директории phpMyAdmin. Предполагается что на локальном компьютере существует папка с файлами <strong>“phpMyAdmin”</strong>, если необходимо, распакуйте архив.</p>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/10-pma-import-sql.jpg" width="800" />
    <figcaption>Настройка phpmyadmin</figcaption>
  </figure>
  <p>Для завершения импорта нажимаем кнопку <strong>“Вперед”</strong>.</p>
  <h3>4. Конфигурация</h3>
  <p>Копируем файл конфигурации из шаблона</p>
  <p><code>cd /var/www/sites/phpMyAdmin/</code></p>
  <p><code>cp config.sample.inc.php config.inc.php</code></p>
  <p>Открываем конфигурационный файл <strong>“/var/www/sites/phpMyAdmin/config.inc.php”</strong> и вносим следующие изменения:</p>
  <ol>
    <li>Задаем произвольное значение длиной 32 символа для параметра <strong>“$cfg[&#x27;blowfish_secret&#x27;]”</strong>. Можно воспользоваться любым генератором паролей.</li>
  </ol>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/11-pma-conf-blowfish.jpg" width="800" />
    <figcaption>Конфигурация phpmyadmin</figcaption>
  </figure>
  <ol>
    <li>Снимаем комментарии со всех строк раздела <strong>“phpMyAdmin configuration storage settings”</strong> и указываем для параметров <strong>“controluser”</strong> и <strong>“controlpass”</strong> логин и пароль служебной учетной записи MariaDB, созданной на предыдущем шаге. В нашем случае логин - <strong>pmaservice</strong>, пароль - <strong>Qwe123</strong></li>
  </ol>
  <figure class="m_original">
    <img src="https://profitserver.ru/files/images/faq/vps-web-server/12-pma-config-storage.jpg" width="800" />
    <figcaption>Конфигурация phpmyadmin</figcaption>
  </figure>
  <p>Сохраняем изменения. Настройка завершена.</p>
  <p><strong>Данные для входа в phpMyadmin:</strong></p>
  <ul>
    <li>http://[ip_адрес_сервера]/pma/</li>
    <li>Логин: pma</li>
    <li>Пароль: Qwe123</li>
  </ul>
  <p>Материал взят с сайта <a href="https://profitserver.ru/knowledge-base/web-server-setup-linux" target="_blank">profitserver.ru</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/easy-vue-js-slider-component</guid><link>https://teletype.in/@iceslam/easy-vue-js-slider-component?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/easy-vue-js-slider-component?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>Простой слайдер-компонент на VueJS</title><pubDate>Wed, 29 Jul 2020 15:09:23 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/78/b6/78b603f4-cce6-4bca-b7da-0e3a7a734496.png"></media:content><category>VueJS</category><description><![CDATA[<img src="https://telegra.ph/file/cee16d553dbde5f3e20a4.png"></img>Сделай слайдер простым...]]></description><content:encoded><![CDATA[
  <p>Сделай слайдер простым...</p>
  <p><strong>Демо</strong>: <a href="https://codesandbox.io/embed/vnynj6o500" target="_blank">CodeSandbox</a></p>
  <h4>Установка</h4>
  <pre>npm i -S vue-easy-slider
</pre>
  <h4>Использование</h4>
  <p>Установка плагина</p>
  <pre>import Vue from &#x27;vue&#x27;
import EasySlider from &#x27;vue-easy-slider&#x27;

Vue.use(EasySlider)
</pre>
  <p>или использование в инстансе Vue</p>
  <pre>&lt;slider animation=&quot;fade&quot;&gt;
  &lt;slider-item
    v-for=&quot;(i, index) in list&quot;
    :key=&quot;index&quot;
    :style=&quot;i&quot;
    @click=&quot;hello&quot;
  &gt;
    &lt;p style=&quot;line-height: 280px; font-size: 5rem; text-align: center;&quot;&gt;Страница{{ index + 1 }}&lt;/p&gt;
  &lt;/slider-item&gt;
&lt;/slider&gt;
</pre>
  <pre>import { Slider, SliderItem } from &#x27;vue-easy-slider&#x27;

new Vue({
  el: &#x27;body&#x27;,
  components: {
    Slider,
    SliderItem,
  },
  data() {
    return {
      list: [
        { backgroundColor: &#x27;#3f51b5&#x27;, width: &#x27;100%&#x27;, height: &#x27;100%&#x27; },
        { backgroundColor: &#x27;#eee&#x27;, width: &#x27;100%&#x27;, height: &#x27;100%&#x27; },
        { backgroundColor: &#x27;#f44336&#x27;, width: &#x27;100%&#x27;, height: &#x27;100%&#x27; },
      ],
    }
  },
  methods: {
    hello($event) {
      console.log(&#x60;hello index: ${$event}&#x60;)
    },
  },
})
</pre>
  <p>Управление слайдером через v-model</p>
  <pre>&lt;slider animation=&quot;fade&quot; v-model=&quot;sliderIndex&quot;&gt;
  ...
&lt;/slider&gt;
&lt;button @click=&quot;moveToIndex(2)&quot;&gt;пролистать на страницу 3&lt;/button&gt;
</pre>
  <pre>...
  data() {
    return {
      // initial index
      sliderIndex: 1,
      list: [
        { backgroundColor: &#x27;#3f51b5&#x27;, width: &#x27;100%&#x27;, height: &#x27;100%&#x27; },
        { backgroundColor: &#x27;#eee&#x27;, width: &#x27;100%&#x27;, height: &#x27;100%&#x27; },
        { backgroundColor: &#x27;#f44336&#x27;, width: &#x27;100%&#x27;, height: &#x27;100%&#x27; },
      ],
    }
  },
  methods: {
    moveToIndex(index) {
      this.sliderIndex = index
    },
  },
...
</pre>
  <h4>Пропсы</h4>
  <p>Слайдер</p>
  <figure class="m_original">
    <img src="https://telegra.ph/file/cee16d553dbde5f3e20a4.png" width="848" />
  </figure>
  <h4>События</h4>
  <p>Слайдер</p>
  <figure class="m_original">
    <img src="https://telegra.ph/file/a2908c4ac76221ba251b7.png" width="805" />
  </figure>
  <h4>Слоты</h4>
  <p>Элемент слайда</p>
  <figure class="m_original">
    <img src="https://telegra.ph/file/30bd10b5371458075b3d3.png" width="285" />
  </figure>
  <p>Использование</p>
  <pre>&lt;slider&gt;
  &lt;slider-item&gt;
    &lt;img src=&quot;&quot;&gt;
    &lt;p&gt;&lt;/p&gt;
    &lt;button&gt;&lt;/button&gt;
  &lt;/slider-item&gt;
  &lt;div slot=&quot;loading&quot;&gt;custom loading ...&lt;/div&gt;
&lt;/slider&gt;
</pre>
  <p>_____________________________________</p>
  <p>Оригинал на <a href="https://github.com/shhdgit/vue-easy-slider" target="_blank">GitHub </a>(автор компонента - <a href="https://github.com/shhdgit" target="_blank">shhdgit</a>)</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@iceslam/vue-2-breadcrumbs-how-to-translated</guid><link>https://teletype.in/@iceslam/vue-2-breadcrumbs-how-to-translated?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam</link><comments>https://teletype.in/@iceslam/vue-2-breadcrumbs-how-to-translated?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=iceslam#comments</comments><dc:creator>iceslam</dc:creator><title>&quot;Хлебные крошки&quot; на VueJS (vue-2-breadcrumbs)</title><pubDate>Wed, 29 Jul 2020 14:59:51 GMT</pubDate><description><![CDATA[Vue-2-breadcrumbs построены на базе официального плагина vue-router для создания простых &quot;хлебных крошек&quot;]]></description><content:encoded><![CDATA[
  <blockquote>Vue-2-breadcrumbs построены на базе официального плагина vue-router для создания простых &quot;хлебных крошек&quot;</blockquote>
  <p>Демо: <a href="https://scrum.github.io/vue-2-breadcrumbs/" target="_blank">GitHub</a></p>
  <h4>Поддержка</h4>
  <ul>
    <li>Поддержка SSR</li>
    <li>Установка родительского маршрута без необходимости фактически вложить его в дочерний массив</li>
    <li>Кастомизированный шаблон</li>
    <li>Динамические &quot;хлебные крошки&quot;</li>
    <li>Динамический родитель</li>
    <li>Динамический заголовок</li>
    <li>Сокращенный заголовок (<code>breadcrumb: &#x27;Заголовок страницы&#x27;</code>)</li>
    <li>Суб-роутинг</li>
  </ul>
  <h4>Установка</h4>
  <pre>npm install vue-2-breadcrumbs
</pre>
  <blockquote><strong>Примечание:</strong> Этот компонент совестим с NodeJS v10+</blockquote>
  <h4>Использование</h4>
  <pre>import Vue from &#x27;vue&#x27;;
import VueBreadcrumbs from &#x27;vue-2-breadcrumbs&#x27;;
import App from &#x27;./App.vue&#x27;;

Vue.use(VueBreadcrumbs);
</pre>
  <blockquote><strong>Примечание</strong>: После этого компонент <code>&lt;Breadcrumbs/&gt;</code> будет в вашем распоряжении</blockquote>
  <p>Мета во Vue Router</p>
  <pre>import Vue from &#x27;vue&#x27;;
import VueRouter from &#x27;vue-router&#x27;;

Vue.use(VueRouter);

const router = new VueRouter({
  routes: [
    {
      path: &#x27;/&#x27;,
      name: &#x27;Главная&#x27;,
      component: { template: &#x27;&lt;h2&gt;Главная&lt;/h2&gt;&#x27; },
      meta: {
        breadcrumb: &#x27;Главная&#x27;
      }
    },
    {
      path: &#x27;/params&#x27;,
      name: &#x27;Параметры&#x27;,
      component: { template: &#x27;&lt;h2&gt;Параметры&lt;/h2&gt;&#x27; },
      meta: {
        breadcrumb: routeParams =&gt; &#x60;route params id: ${routeParams.id}&#x60;
      }
    },
    {
      path: &#x27;/context&#x27;,
      name: &#x27;Контекст&#x27;,
      component: { template: &#x27;&lt;h2&gt;Контекст&lt;/h2&gt;&#x27; },
      meta: {
        breadcrumb() {
            const { name } = this.$route;
            return &#x60;Имя &quot;${name}&quot; рута контекста&#x60;;
        }
      }
    },
    {
      path: &#x27;/parent&#x27;,
      component: { template: &#x27;&lt;router-view/&gt;&#x27; },
      meta: {
        breadcrumb: {
          label: &#x27;Родитель для параметров&#x27;,
          parent: &#x27;Параметры&#x27;
        }
      },
      {
        name: &#x27;dynamic-parent&#x27;,
        path: &#x27;/dynamic-parent&#x27;,
        component: { template: &#x27;&lt;h2&gt;Динамический родитель&lt;/h2&gt;&#x27; },
        meta: {
          breadcrumb() {
            const { name } = this.$route;

            return {
              label: name,
              parent: &#x27;settings&#x27;
            };
          }
        }
    }
  ]
});
</pre>
  <h4>Опции</h4>
  <p>Объект options также может быть передан в плагин для указания вашего собственного шаблона и методов рендеринга при желании. Например:</p>
  <pre>import Vue from &#x27;vue&#x27;;
import VueBreadcrumbs from &#x27;vue-2-breadcrumbs&#x27;;

Vue.use(VueBreadcrumbs, {
  template:
    &#x27;        &lt;nav v-if=&quot;$breadcrumbs.length&quot; aria-label=&quot;breadcrumb&quot;&gt;\n&#x27; +
    &#x27;            &lt;ol class=&quot;breadcrumb&quot;&gt;\n&#x27; +
    &#x27;                &lt;li v-for=&quot;(crumb, key) in $breadcrumbs&quot; v-if=&quot;crumb.meta.breadcrumb&quot; :key=&quot;key&quot; class=&quot;breadcrumb-item active&quot; aria-current=&quot;page&quot;&gt;\n&#x27; +
    &#x27;                    &lt;router-link :to=&quot;{ path: getPath(crumb) }&quot;&gt;{{ getBreadcrumb(crumb.meta.breadcrumb) }}&lt;/router-link&gt;&#x27; +
    &#x27;                &lt;/li&gt;\n&#x27; +
    &#x27;            &lt;/ol&gt;\n&#x27; +
    &#x27;        &lt;/nav&gt;&#x27;
});
</pre>
  <p>_________________________</p>
  <p>Оригинал на <a href="https://github.com/Scrum/vue-2-breadcrumbs" target="_blank">Github </a>(автор компонента - <a href="https://github.com/Scrum" target="_blank">Scrum(Иван Демидов)</a>)</p>

]]></content:encoded></item></channel></rss>