Hosten von Node.js https-Server mit automatisch aktualisiertem SSL in der Cloud und wie ich den Entwicklungszyklus einrichte (+ git, reagieren)

Vorwort


Zunächst wollte ich eines Tages eine Anwendung erstellen. Dieser Wunsch entstand, weil ich gerne lese, aber es gibt einfach keine normalen Buchaggregatoren im riesigen russischen Internet. Aus dem Schmerz heraus, nach etwas zum Lesen zu suchen und zu versuchen, sich an den Namen des Buches zu erinnern, das ich kürzlich gelesen habe, und an das Kapitel, bei dem ich angehalten habe, entstand der Wunsch, eine Webanwendung zu erstellen, in der all dies möglich und bequem wäre. Es ist erwähnenswert, dass keine Erfahrung in Entwicklung, Programmierung usw. Ich hatte keine, meine Arbeit ist damit überhaupt nicht verbunden. Trotzdem überwand das Verlangen die Faulheit und entwickelte sich zu konkreten Handlungen, einer Art Hobby.

Ich werde nicht sagen, wie ich Javascript, node.js, Reaktion, HTML, CSS usw. studiert habe. Wir werden zu dem übergehen, worauf ich gerade gekommen bin, was ich mit Ihnen teilen möchte und natürlich konstruktive Kritik an Spezialisten hören.

Wie viele andere habe ich auf localhost auf meinem eigenen PC trainiert: 3000, Front / Back-Ends erstellt, gesetzt, mit API gearbeitet usw., aber ich war immer besorgt darüber, wie ich das alles später auf das Hosting übertragen kann? Wird es funktionieren? Wird es aus diesem Grund notwendig sein, den Code neu zu schreiben? Und was am wichtigsten ist: Ist es möglich, alles so zu konfigurieren, dass ich von jedem PC aus an der Anwendung arbeiten und alles problemlos auf das Hosting in der Produktion übertragen kann? Ich werde darüber sprechen.

Hosting-Wahl


Für mein Hobby war ich bereit, 10 US-Dollar im Monat auszugeben, und entschied mich für das Hosting, bei dem ich in Zukunft bleiben wollte. Wie gesagt, vorher hatte ich 0 Erfahrung, auch mit Site-Hosting. Ich habe Folgendes versucht und abgelehnt:

Jelastic : schöne und benutzerfreundliche Oberfläche, alles scheint intuitiv, skalierbar und verständlich zu sein. Trotzdem hatte ich Schwierigkeiten beim Einrichten (nginx wollte aus irgendeinem Grund nicht von vps aus arbeiten, nur mit ihrem separaten Modul) und beim Verbinden von SSL (und automatischer Aktualisierung) mit der russischsprachigen Domain mit Standardmitteln (sie versprachen, den Fehler zu beheben, aber ich möchte nicht warten)

Cloud-Hosting REG.RU : Ich habe genau dort auch eine Domain, daher schien die Lösung logisch, aber PostgreSQL war nicht separat konfiguriert. Da ich mich nicht an die Datenbankverwaltung wenden wollte, suchte ich weiter.

AWS und Google Clouds : Ich habe es versucht, alles scheint in Ordnung zu sein, aber ich erinnerte mich an unsere „wunderbaren“ Gesetze und die Anforderung, Benutzerdaten auf Servern in der Russischen Föderation zu speichern. Leider hatten diese Leute keine Server in der Russischen Föderation. Kein Anwalt, sondern aus Sünde beschlossen, nach Clouds mit Servern in der Russischen Föderation zu suchen. Wenn es unwahrscheinlich ist, dass Ihre Bewerbung Probleme mit dem Gesetz hat, ist dies eine gute Wahl.

Obwohl es in der Russischen Föderation Clouds mit Servern gab, wollte ich immer noch etwas, das mich davon abhält, in die PostgreSQL-Administration einzutauchen. Der Impuls kam vor nicht allzu langer Zeit auf Yandex.Wolken , die verfügbar wurden, habe ich versucht, es scheint, dass alles einfach und bequem ist, also habe ich vorerst bei ihnen angehalten. Es ist erwähnenswert, dass das PostgreSQL-Hosting sofort mit 1core und 4 GB RAM geliefert wird, was ungefähr 2.000 Rubel pro Monat kostet. Für die Zeit der Entwicklung und der geringen Auslastung plane ich, PostgreSQL auf VPS für ~ 300r auszuführen und die Datenbank mit erhöhter Auslastung zu übertragen und zuzulassen Yandex ist mit der Verwaltung und Aktualisierung beschäftigt.

Yandex.Cloud einrichten


Virtuelle private Cloud


1) Erstellen Sie ein Verzeichnis für Ihre Site:

Bild

2) Erstellen Sie eine virtuelle private Cloud:

Die Hauptsache, die er mir derzeit gibt, ist die IP, um von außen auf die erstellte Ressource zuzugreifen. Ich habe mich oberflächlich mit Subnetzen, Zonen, Isolation und Fehlertoleranz vertraut gemacht, wenn nötig, werde ich aufholen.

3) Erstellen Sie ein Subnetz und weisen Sie ihm eine interne IP zu (so wie ich es verstehe, handelt es sich um ein lokales Netzwerk).

Bild

4) Gehen Sie zur Registerkarte IP und reservieren Sie sich eine statische IP.

Darauf werden wir uns von zu Hause und anderen Orten aus verbinden. Sie können wahrscheinlich mit Dynamic arbeiten, aber ich habe nicht verstanden, in welchen Fällen sich dies ändert.

Bild

Cloud berechnen


Hier werden wir Berechnungen haben :) Das heißt, wir werden eine virtuelle Maschine mit Linux erstellen (ich habe Ubuntu 18.04 gewählt), node.js-Anwendungen und postgreSQL installieren.

Bild

Wir klicken, um eine VM zu erstellen, und schrauben alle Einstellungen auf ein Minimum ab, da während der Entwicklung keine Last entsteht (wenn unsere Anwendung veröffentlicht wird, drehen Sie sie ein wenig weiter, und wir werden sie anhand der Grafiken überwachen).

Ssh


Der Problempunkt, auf den ich zu diesem Zeitpunkt gestoßen bin, ist SSH:

Bild

Was es war und warum ich keine Ahnung hatte, ging ich zum Lernen. Es stellte sich heraus, dass dies nur eine Zugriffsmethode ist, jedoch nicht über das Kennwort, sondern über den generierten SSH-Schlüssel. Laden Sie Putty herunter und installieren Sie es, um es tatsächlich zu generieren.

Führen Sie C: \ Programme \ PuTTY \ puttygen.exe aus

Bild

Wir drücken die Generieren-Taste und bewegen die Maus, um der generierten Taste Zufälligkeit zu verleihen (so wie ich es verstehe). Kopieren Sie als Nächstes die Zeile, die mit ssh-rsa beginnt, irgendwo in die Textdatei und klicken Sie auf Privaten Schlüssel speichern, Öffentlichen Schlüssel speichern. Der in die Textdatei kopierte Schlüssel wird in das SSH-Feld des Schlüssels der Yandex Yandex-Seite eingefügt. Wir geben root als Login an, andernfalls haben Sie keinen Zugriff, wenn Sie mit dem Grafikdateisystem der Anwendung arbeiten, über das Sie von zu Hause / von der Arbeit aus eine Verbindung zur Cloud herstellen (möglicherweise gibt es einen Weg, aber ich habe ihn nicht verstanden).
Wie von andreymal festgestellt, ist es besser, root nicht zu verwenden, damit chinesische Bots das Passwort für Ihre Cloud nicht abrufen. Da Yandex.cloud jedoch nur über SSH-Zugriff verfügt, können Sie so leben.

Eine Anwendung auf einem Hosting sollte ausschließlich von einem Nicht-Root-Benutzer gestartet werden, damit Angreifer keinen schädlichen Code durch mögliche Schwachstellen in Ihrer Anwendung ausführen können.


Wir stellen von einem PC aus eine Verbindung zur Cloud her und wählen einen kostenlosen SSH-Client aus


Mit dem Standard-Putty können Sie nur in der Befehlszeile arbeiten. Da ich mit dem Windows-Benutzer nicht vertraut bin, habe ich nach einem Client mit einem Pseudo-Explorer gesucht. Zuerst habe ich Mobaxterm ausprobiert, aber nach einiger Zeit der Inaktivität wird es heruntergefahren, der Explorer friert vollständig ein. Jetzt arbeite ich mit bitvise ssh und sehe bisher keine Probleme wie Mobaxterm.

Konfigurieren Sie bitvise ssh


Bild

Geben Sie hier im Feld Server> Host unsere externe IP-Cloud an. Port 22. Klicken Sie auf Client Key Manager> Importieren und geben Sie den zuvor generierten privaten Schlüssel an. Möglicherweise benötigen Sie noch einen Schlüsselbegriff. Wählen Sie etwas aus, das Sie nicht vergessen werden. Schließen Sie dieses Fenster und geben Sie den Benutzernamen im Authentifizierungsfeld an: root, Methodenveröffentlichungsschlüssel, Clientschlüssel - wählen Sie den zuvor importierten aus. Klicken Sie auf Anmelden. Wenn wir alles richtig gemacht haben, stellen Sie eine Verbindung zur Cloud her:

Bild

Installieren Sie Node.js.


Hier empfehle ich die Anweisungen von digitalocean.com zu verwenden, sie sind sehr detailliert und viele sind in russischer Sprache. Normalerweise google ich "digitalocean ubuntu 18.04 node.js" oder was auch immer Sie dort installieren oder konfigurieren möchten.

Wie Sie Node.js installieren, lesen Sie hier .

Kurz gesagt, wir gehen zu nodeource (hier können die neuesten Versionen von node.js installiert werden) und blättern hier durch:

Bild

Kopieren Sie die Befehle und führen Sie sie nacheinander aus:

curl -sL https://deb.nodesource.com/setup_11.x | sudo -E bash - sudo apt-get install -y nodejs 

Wir überprüfen, wie es vom Team eingerichtet wurde

 nodejs -v 

Wir werden die Version von node.js sehen

 npm -v 

Wir sehen die Version des Paketmanagers für node.js.

Wechseln Sie als Nächstes zum Ordner / opt / mysuperapp (my_super_app_name - Sie müssen diesen Ordner erstellen). Das opt-Verzeichnis wurde nach langem googeln als Speicherort der Anwendung ausgewählt, "wo es angebracht ist, die node.js-Dateien der Anwendung in ubuntu abzulegen".

Erstellen Sie abschließend die Datei server.js, die der Einstiegspunkt der Anwendung sein wird, und fügen Sie dort den einfachen Servercode in node.js ein:

 const http = require('http'); const hostname = 'localhost'; const port = 80; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World!\n'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); }); 

Port 80 ist für http-Anfragen, 443 für https. Während wir einen Server auf http haben.

Wir speichern alles und führen den Befehl aus:

 node server.js 

In der Konsole sollte die Zeile "Server läuft auf localhost : 80 /" angezeigt werden.

Jetzt können Sie einen Browser öffnen, eine externe IP eingeben (die in der Yandex-Cloud Ihrer Ubuntu-VM) und wir sehen "Hallo Welt!"

Wir machen alles bequem oder den Entwicklungszyklus mit git


Alles scheint zu funktionieren, aber wir werden nicht die ganze Zeit daran arbeiten, eine Verbindung zur Cloud herzustellen. Außerdem werden wir in Zukunft plötzlich nicht mehr alleine arbeiten.

Github


Github ist der Ort, an dem der Code unserer Anwendung liegen wird. Kurz gesagt, das Arbeitsprinzip für eine Person lautet wie folgt:

  • Wir entwickeln unsere Anwendung auf einem Heim-PC.
  • Wir speichern und entladen den Code auf Github mit einem Klick.
  • Laden Sie auf dem Hosting oder auf einem anderen PC unsere Anwendung von github herunter, starten Sie den Server neu (falls er gehostet wird) und die neue Version unserer Webanwendung ist im World Wide Web verfügbar.

Alles ist schnell, einfach und bequem.

Registrieren Sie sich tatsächlich bei Github und erstellen Sie ein privates Repository für unsere Anwendung (es steht nur uns zur Verfügung):

Bild

Kopieren Sie die Zeile github.com/ReTWi/mysuperapp.git , um die Anwendung herunterzuladen.

Bild

  1. Wir kehren zur Bitvise-Befehlszeile zurück und stoppen die Anwendung durch Drücken von Strg + C (falls dies noch funktioniert).
  2. Wechseln Sie in das Verzeichnis / opt und löschen Sie den Ordner mit der von uns erstellten Anwendung

Git wird verwendet, um unsere Anwendung auf github und von dort auf ein Hosting oder einen anderen PC hochzuladen. Git ist ein separates Diskussionsthema, also lassen Sie uns zunächst darauf eingehen.
Installieren Sie git auf dem Hosting mit den folgenden Befehlen:

 sudo apt update sudo apt install git 

Überprüfen Sie, ob alles gut etabliert ist:

 git --version 

Die Git-Version sollte erscheinen.

Wir geben die Git-Daten ein (ich habe nicht verstanden, warum, aber anscheinend gibt es einige langweilige Warnungen).

 git config --global user.name "Your Name" git config --global user.email "youremail@domain.com" 

Schließlich laden wir unsere Anwendung mit dem folgenden Befehl auf das Hosting hoch:
(Es sollte einen Link zu Ihrer Bewerbung geben.)

 git clone https://github.com/ReTWi/mysuperapp.git 

Eine neue mysuperapp wird im Verzeichnis / opt angezeigt, in dem sich unsere von github heruntergeladenen Anwendungsdateien befinden.

Jetzt ist es Zeit, dasselbe für den PC zu wiederholen und die PC-Kette zu schließen (anders) -> Github -> Hosting

Installieren Sie node.js auf dem PC .

Visual Studio Code


Wählen Sie zunächst den Quellcode-Editor aus, in dem wir arbeiten werden. Ich habe mich für Visual Studio-Code entschieden, damit er einfach und bequem ist, viele Plugins enthält und Sie die Synchronisierung von Einstellungen konfigurieren können, wenn Sie mit mehreren Geräten arbeiten. Tatsächlich laden wir den freigegebenen Anwendungsordner herunter, installieren ihn, starten ihn und wählen ihn aus, da der Git-Klon einen eigenen für uns erstellt.

Die Plugins, die ich benutze, sind wie folgt:

Bild

Installieren Sie git für PC .
Öffnen Sie eine Konsole in VScode mit Strg + Umschalt + `oder Terminal> Neues Terminal

Rückzug:

In der Windows-Konsole ist es schlecht mit russischen Zeichen, so dass es keine Risse gibt, die Sie zum Öffnen von Datei> Einstellungen> Einstellungen benötigen. Geben Sie terminal.integrated.shellArgs.windows in das Feld ein und klicken Sie auf

Bild

Und fügen Sie die Zeile "terminal.integrated.shellArgs.windows" hinzu: ["-NoExit", "/ c", "chcp 65001"],

Bild


Wiederholen Sie den Befehl, um Dateien von github herunterzuladen:

 git clone https://github.com/ReTWi/mysuperapp.git 

Klicken Sie in VScode auf Datei> Ordner öffnen und öffnen Sie den Ordner unserer Anwendung.

Erstellen Sie die Datei server.js mit demselben einfachen Servercode:

 const http = require('http'); const hostname = 'localhost'; const port = 80; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World!\n'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); }); 

Installieren Sie nodemon, um den Server automatisch neu zu starten, wenn Änderungen am Code vorgenommen werden:

 npm i nodemon -g 

i - kurz für install
g - globale Installation (verfügbar in der Konsole) und nicht nur für unsere Anwendung.

Führen Sie den folgenden Befehl aus:

 nodemon server.js 

Öffnen Sie localhost : 80 / im Browser oder einfach localhost: 80 und sehen Sie Hello World.

Jetzt ist es Zeit, unsere PC-Kette> Github> Hosting zu besuchen.

Laden Sie den Github-Desktop für mehr Komfort herunter, verbinden Sie Ihr Github-Konto, klicken Sie auf die Datei zum Hinzufügen eines lokalen Repositorys und geben Sie das Verzeichnis unserer Anwendung an.

In der Anwendung sehen wir die Änderungen, die wir gegenüber der von Github heruntergeladenen Version vorgenommen haben (wir haben server.js hinzugefügt):

Bild

Klicken Sie auf "Commit to Master"> "Push Origin", um Dateien vom PC auf Github herunterzuladen.

Bild

Wir gehen zu unserem Github-Konto im Browser und sehen die heruntergeladene Datei server.js:

Bild

Lassen Sie uns etwas mehr üben, in VScode ersetzen wir die Zeile "res.end ('Hello World! \ N');" zu "res.end ('OmNomNom');". Wir werden sehen, dass der Server selbst neu gestartet wurde:

Bild

Wir werden im Browser nachsehen, welche Änderungen wir dort "OmNomNom" vorgenommen haben.

Desktop Github zeigt uns auch, dass wir die Zeile geändert haben:

Bild

Klicken Sie erneut auf Commit to Master> Push Origin, um Dateien an Github zu senden.

Wechseln Sie zur Hosting-Befehlszeile.

Wir stoppen unsere Anwendung, wenn sie noch ausgeführt wird (Strg + C).

Laden Sie unsere aktualisierte Anwendung mit den folgenden Befehlen herunter:

 git config credential.helper store git pull 

Der erste speichert unsere Daten, damit Sie Ihr Login und Passwort nicht ständig eingeben müssen. In Zukunft wird uns Git Pull ausreichen.

Installieren Sie pm2 - ähnlich wie nodemon, nur für das Hosting:

 npm i pm2 -g 

Starten wir die Anwendung mit pm2, wodurch unser Server beim nächsten Git-Pull auf dem Hosting neu gestartet wird:

 pm2 start server.js --watch 

Öffnen Sie den Browser in unserer externen IP-Cloud und sehen Sie sich unser „OmNomNom“ an.

Daher haben wir die Arbeitskette mit der Anwendung und deren schnelle Bereitstellung auf dem Hosting geschlossen.

Wir erstellen temporäre SSL-Zertifikate für HTTPS auf localhost und Hosting


Wir gehen auf die Seite zerossl.com

Bild

Geben Sie im Feld Domains, IP ... zuerst localhost ein, klicken Sie auf 2 Dateien generieren und laden Sie sie herunter:

Bild

Wir speichern sie in unserem Projekt im Ordner ssl / localhost.

Wiederholen Sie den Vorgang für die externe IP Cloud und speichern Sie sie in ssl / myapp.

Starten Sie einen komplexeren https-Server node.js


Anwendungsstruktur:

Bild

  • Kunde - hier liegt unser Frontend. Ich habe reagiert
  • Protokolle - Protokolle beim Hosting werden hier gelöscht
  • node_modules - node.js Module
  • privat - Ihre privaten Dateien speichere ich dort SSH-Zugriff auf die Cloud
  • Server ist dein Backend
  • ssl - ssl-Zertifikate für die Arbeit mit https auf localhost und Hosting
  • .babelrc - Webpack'om-Anwendung reagiert auf Build-Einstellungen (ermöglicht die Verwendung modernerer JS bei der Entwicklung des Frontends)
  • .gitignore - Dateien, die nicht nach github verschoben werden (git scheint sie nicht zu sehen)
  • client.js - Einstiegspunkt zum Generieren einer Reaktionsassemblierung
  • package.json - die von Ihnen verwendeten node_modeles und verschiedene Befehlsausschnitte.
  • package-lock.json - Änderungen in den Modulen (so wie ich es verstehe, prüft die Datei, ob dieselben Module auf Ihrem Hosting und auf Ihrem PC installiert sind).
  • pm2-watch.json - pm2 Starteinstellungen für das Hosting
  • README.md - Abdeckung für Github
  • server.js - der Ausgangspunkt unseres Backend Node.js-Servers
  • webpack.config.js - Build-Konfiguration reagieren

.gitignore


Hier geben wir die Dateien / Ordner an, die wir nicht auf github hochladen möchten. Sie werden nur auf diesem Gerät sein und Git wird ihre Änderungen nicht verfolgen / anzeigen. Öffnen und einfügen:

 /node_modules/ /logs/* # exception to the rule !logs/.gitkeep /public/react_bundle.js /public/isProd.js 

Da github keine leeren Ordner entlädt, können Sie beispielsweise etwas in eine leere .gitkeep-Datei einfügen. Speichern Sie die Datei und schließen Sie sie.

package.json


Öffnen und fügen Sie Folgendes ein (nach // hinzugefügten Kommentaren)

 { "name": "myapp", //    "version": "1.0.0", "description": "OmNomNom", "main": "server.js", "scripts": { "server": "pm2 start pm2-watch.json", //  npm run server     "client": "webpack -w --mode development", //  npm client    .        ,   . "client-prod": "webpack --mode production", //     production "client-analyze": "webpack --mode production --analyze true" //     production       .    }, "repository": { "type": "git", "url": "git+https://github.com/myapp/knigam.git" //     github }, "author": "rtw", "license": "UNLICENSED", //     ( ) "bugs": { "url": https://github.com/myapp/knigam.git" }, "homepage": "https://github.com/myapp/knigam.git#readme", "dependencies": { "@babel/core": "^7.2.2", //  js  frontend "@babel/plugin-transform-runtime": "^7.2.0", //  js  frontend "@babel/preset-env": "^7.3.1", //  js  frontend "@babel/preset-react": "^7.0.0", //  js  frontend "ajv": "^6.8.1", //    "babel-loader": "^8.0.5", //  js  frontend "babel-plugin-styled-components": "^1.10.0", //   styled-components "css-loader": "^2.1.0", //   webpack'om css "fastify": "^2.0.0-rc.6", //  express,      "fastify-cookie": "^2.1.6", //    "fastify-static": "^2.2.0", //     "moment": "^2.24.0", //    "pg": "^7.8.0", //    "pino": "^5.11.1", //   postgreSQL  node.js "pino-pretty": "^2.5.0", //     "react": "^16.8.1", // Frontend .      Vue.js,    .      ,     "react-dom": "^16.8.1", // React     "style-loader": "^0.23.1", //   webpack'om ,    "styled-components": "^4.1.3", // CSS in JS,           "webpack": "^4.29.3", //    "webpack-bundle-analyzer": "^3.0.3", //       "webpack-cli": "^3.2.3" //    ,     } } 

Ich werde mich auf zwei Haupt-Frameworks / Bibliotheken konzentrieren, die für die Anwendung ausgewählt wurden:
Fastify wurde als Alternative zu express.js gewählt, da das erste bereits experimentelle Unterstützung für htpp2 hat, es sich aktiv entwickelt und es scheint mir, dass es mehr Zukunft hat als express.js, das sehr langsam geworden ist und sich irgendwie entwickelt. Auf der anderen Seite arbeitet express.js schon lange und es wird für Sie einfacher sein, Informationen darüber zu finden.

React wurde gewählt, weil es für mich einfacher war, damit zu arbeiten, alles zu verstehen und mit meinen eigenen Händen zu versuchen. Vue - es schien etwas mit seinen eigenen Regeln, Richtungen. In Vue kann es zwar notwendig sein, etwas weniger mit den eigenen Händen zu schreiben, aber da der Schwerpunkt auf dem Training und für eine Person liegt, die zuvor nicht programmiert hat, war die Reaktion irgendwie einfacher.

Wir speichern die Datei package.json und installieren alle in Abhängigkeiten angegebenen Module mit dem folgenden Befehl:

 npm i 

Wir werden einen Ordner node_modules haben, in dem sich alle Module für unsere Anwendung befinden.

client - während der leere Ordner
Protokolle - in der .gitkeep-Datei liegt, so dass der Ordner zum Hosting migriert wird und die Protokolle dort erfolgreich abgelegt werden. Während der Entwicklung geben wir alles auf der Konsole aus.

Öffentlichkeit


Hier liegen die statischen Dateien unserer Seite, Bilder dort, Favoriten usw.
Lassen Sie uns auf zwei Dateien eingehen:
index.html:

 <!DOCTYPE html> <html> <head> <base href="/" /> <meta charset="UTF-8" /> <title>MyApp</title> </head> <body> <div id="cookies">    react_bundle   </div> <noscript >:       Javscript</noscript > <script src="react_bundle.js"></script> </body> </html> 

- Hier haben wir ein Reaktions-Frontend geladen und durch seine ID in ein Tag gerendert.

isProd.js enthält eine einzelne Zeile "module.exports = false"
Da es sich um .gitignore-Ausnahmen handelt, ist es nicht portierbar. Dementsprechend setzen wir es auf dem PC auf false und auf dem Hosting auf true. Dann verwenden wir diese Datei, um zu verstehen, in welcher Umgebung wir uns gerade befinden (Entwicklung / Produktion). Es schien mir am bequemsten, außerdem können Sie den Code während der Entwicklung teilweise ändern und den Betrieb von Modulen in der Produktion überprüfen.

ssl - In den Ordnern localhost und myapp befinden sich zuvor gespeicherte Zertifikate

.babelrc


 { "presets": [ [ "@babel/preset-env", { "targets": { "browsers": [">0.25%", "not ie 11", "not op_mini all"] } } ], "@babel/preset-react" ], "plugins": [ "babel-plugin-styled-components", "@babel/plugin-transform-runtime" ] } 

Einstellungen zum Erstellen unseres react_bundle mit Browserunterstützung, die von mehr als 0,25% der Benutzer verwendet wird.

client.js


 import React from 'react' import { render } from 'react-dom' render(<div>!!</div>, document.getElementById('cookies')) 


Rendert unser Frontend in einem Div mit einem Cookie-Tag.

pm2-watch.json - Ermöglicht das Ausführen des Servers mit dem Befehl "npm run server" auf dem Hosting, wobei Änderungen im Code verfolgt und automatisch neu gestartet werden.

webpack.config.js


Builder für Reaktoranwendungen:

 const webpack = require('webpack'), path = require('path'), BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin module.exports = (env, argv) => { let prod = argv.mode == 'production' let config = { entry: './client.js', output: { path: path.resolve('./public'), filename: 'react_bundle.js' }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader' }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] }, resolve: { alias: { client: path.resolve('./client/shared'), public: path.resolve('./public') } }, plugins: [ argv.analyze ? new BundleAnalyzerPlugin() : false, prod ? new webpack.optimize.AggressiveMergingPlugin() : false, new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /ru/) ].filter(Boolean), optimization: { minimize: prod ? true : false }, performance: { hints: false } } return config } 

Kurz gesagt, er öffnet die Datei client.js und alles, was sich darin befindet, sammelt react_bundle und legt sie im öffentlichen Ordner ab, von wo aus sie über die geöffnete index.html geladen wird.

server.js


 const isProd = require('./public/isProd'), fs = require('fs'), log = require('./server/logger'), path = require('path') //   node.js,      process.on('unhandledRejection', (reason, promise) => { log.error({ reason, promise }, '  unhandledRejection') }) process.on('uncaughtException', err => { log.error({ err }, '  uncaughtException') }) // Redirect server from http port 80 to https 443 const fastifyHttp = require('fastify')({ logger: log, ignoreTrailingSlash: true }) fastifyHttp.listen(80, '::', (err, address) => { if (err) { log.error({ err, address }, '   HTTP ') } else { log.warn('Http c ') } }) // Let's Encrypt challenge fastifyHttp.get('/.well-known/acme-challenge/:file', (req, res) => { let stream = fs.createReadStream( path.join(__dirname + '/ssl/.well-known/acme-challenge/' + req.params.file) ) res.type('text/html').send(stream) }) fastifyHttp.get('/*', (req, res) => { res.redirect(301, 'https://' + req.headers.host + req.raw.url) }) fastifyHttp.get('/', (req, res) => { res.redirect(301, 'https://' + req.headers.host + req.raw.url) }) //  let fastifyOptions = { logger: log, ignoreTrailingSlash: true, http2: true } fastifyOptions.https = isProd ? { allowHTTP1: true, key: fs.readFileSync('./ssl/myapp/key.txt'), cert: fs.readFileSync('./ssl/myapp/crt.txt') } : { allowHTTP1: true, key: fs.readFileSync('./ssl/localhost/cert.key'), cert: fs.readFileSync('./ssl/localhost/cert.pem') } const fastify = require('fastify')(fastifyOptions) fastify.listen(443, '::', (err, address) => { if (err) { log.error({ err, address }, '   ') } else { log.warn( `   ${ isProd ? '' : ' ' }` ) } }) //  fastify.setSchemaCompiler(schema => { return ajv.compile(schema) }) //  fastify fastify.setErrorHandler((err, req, res) => { log.error({ err, req }, 'fastify errorHandler') //     if (err.validation) { return res.send({ error: '   ' }) } else { return res.send({ error: ' errorHandler' }) } }) //   fastify.register(require('fastify-static'), { root: path.join(__dirname, './public') }) //  fastify.register(require('fastify-cookie'), err => { if (err) log.error({ err }, 'fastify-cookie') }) //       /   //       index.html,     //        api,   GET /api/userdata fastify.setNotFoundHandler((req, res) => { res.sendFile('index.html') }) // Routes fastify.register( async openRoutes => { //    openRoutes.register(require('./server/api/open')) openRoutes.register(async withSession => { //         //    , : ///withSession.addHook('preHandler', async (req, res) => { // if (!(await sessionManagerIsOk(req, res))) return // }) withSession.register(require('./server/api/with_session')) }) }, { prefix: '/api' } //    ) 

Serverordner


Hier liegt das Backend und alle Wege.
logger.js - Abhängig von der Umgebung protokolliert isProd entweder in der Konsole oder in Errors.log

 'use strict' const pino = require('pino'), isProd = require('../public/isProd') let logOptions = isProd ? { level: 'warn', //   timestamp: () => { return ',"time":"' + new Date() + '"' } } : { level: 'warn', prettifier: require('pino-pretty'), prettyPrint: { levelFirst: true, translateTime: true } } let dest = isProd ? pino.destination('./logs/errors.log') : pino.destination(1) let log = pino(logOptions, dest) module.exports = log 

server / api /
open.js - fügen Sie hier unsere Pfade hinzu.

 'use strict' module.exports = function(fastify, options, next) { fastify.route({ method: 'GET', url: '/', handler: async (req, res) => { res.send('api / route') } }) fastify.route({ method: 'GET', url: '/hi', handler: async (req, res) => { res.send('api / route hi') } }) next() } 

Nachdem wir alles auf Localhost eingerichtet und überprüft haben, laden wir einfach alles auf github hoch und ziehen von dort aus git zum Hosting. Auf dem Hosting müssen lediglich die Module node.js mit dem Befehl „npm i“ installiert und die Datei isProd.js erstellt werden

SSL wird automatisch aktualisiert


Wenn Sie eine Domain kaufen und an die IP-Cloud binden, ein Beispiel für Anweisungen für REG.RU , können Sie automatisch aktualisiertes kostenloses SSL auf dem Server installieren, damit die Site über https funktioniert.

Unser Server arbeitet ohne Nginx. Wir werden es möglicherweise in Zukunft als Load Balancer oder als schnelleren HTTP-Server für die Verteilung statischer Dateien benötigen, aber bisher sehe ich keine Notwendigkeit dafür. Wir brauchen noch keinen Lastausgleich, aber ich habe keine Vergleiche hinsichtlich der Verteilungsgeschwindigkeit der Statik gefunden.

Erstellen Sie vor der Installation im SSL-Ordner den bekannten Ordner und darin die Acme-Challenge. Es stellt sich heraus, dass /opt/myapp/ssl/.well-known/acme-challenge

Klicken Sie auf den Link, um automatisch aktualisiertes SSL auf einem Server mit node.js ohne nginx zu installieren. Führen Sie die folgenden Befehle in der Hosting-Konsole aus:

 sudo apt-get update sudo apt-get install software-properties-common sudo add-apt-repository universe sudo add-apt-repository ppa:certbot/certbot sudo apt-get update sudo apt-get install certbot sudo certbot certonly 

Wir wählen die zweite Überprüfungsmethode aus, mit der eine bestimmte Datei im Ordner /opt/myapp/ssl/.well-known/acme-challenge abgelegt wird. Nach Bestätigung des Besitzers des Servers wird sie gelöscht.

Wir geben unsere Domain auf Anfrage an, zum Beispiel: "example.com" und den Pfad zum SSL-Ordner unserer Anwendung (der Server ist so konfiguriert, dass er die vom Bot erstellte Datei liefert) "/ opt / myapp / ssl".

Der Bot konfiguriert die Cron-Task selbst so, dass das Zertifikat vor Ablauf innerhalb von 90 Tagen erneuert wird.

Ich hätte nicht gedacht, dass es so lange dauern würde, alles zu schreiben. Um 4 Uhr morgens hätte ich schon etwas verpassen können: /

Interessant ist die Meinung der Habrachianer und Spezialisten, die diese Leinwand beherrschen oder einzelne Punkte lesen. Wie ist Ihr Entwicklungszyklus aufgebaut? Gibt es Punkte, in denen ich mich irre oder das Falsche tue?

Source: https://habr.com/ru/post/de439952/


All Articles