{"id":71378,"date":"2020-02-25T20:45:02","date_gmt":"2020-02-25T17:45:02","guid":{"rendered":"https:\/\/prohoster.info\/blog\/openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij"},"modified":"2020-03-03T16:14:21","modified_gmt":"2020-03-03T13:14:21","slug":"openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij","title":{"rendered":"OpenResty: Transforming NGINX into a Full-Fledged Application Server","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/62eb484051c7963c96842393884ddd98.jpg\" style=\"display:block;margin: 0 auto;\" \/><em>We are publishing the transcript of the talk from the conference again <noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/\">HighLoad++<\/a><\/noindex> 2016, which took place in Skolkovo, near Moscow, on November 7-8 last year. <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/post\/315726\/\">Vladimir Protasov<\/a><\/noindex> discusses how to extend NGINX functionality with OpenResty and Lua.<\/em><\/p>\n<p>Hello everyone, my name is Vladimir Protasov, I work at Parallels. Let me tell you a bit about myself. For three-quarters of my life, I have been writing code. I became a programmer to the bone: I sometimes see code in my dreams. A quarter of my life has been spent in industrial development, writing code that goes straight to production. The code you use, though you might not realize it.<\/p>\n<p>To give you an idea of how bad things were. When I was a young junior, I came in and was handed these two-terabyte databases. Nowadays, everyone has high load systems. I went to conferences, asking: \"Guys, tell me, you have big data, everything is cool? How large are your databases?\" They replied: \"We have 100 gigabytes!\" I thought: \"Cool, 100 gigabytes!\" But inside, I was trying to keep a poker face. You think, yes, these guys are cool, but then you go back and deal with these multi-terabyte databases. And that was as a junior. Can you imagine what a hit that was?<\/p>\n<p>I know over 20 programming languages. This is what I had to figure out during my work. You are handed code in Erlang, C, C++, Lua, Python, Ruby, and some other languages, and you have to work with all of it. In general, it was necessary. I couldn\u2019t quite count the exact number, but I lost track around 20.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nSince everyone here knows what Parallels is and what we do, I won\u2019t talk about how great we are or what we do. I will just mention that we have 13 offices worldwide, over 300 employees, and development teams in Moscow, Tallinn, and Malta. If you want, you can move to Malta if it\u2019s cold in winter and you need to warm up.<\/p>\n<p>Specifically, our department writes in Python 2. We are in business and don\u2019t have time to implement trendy technologies, which is why we struggle. We use Django because it has everything we need, and we\u2019ve discarded what was unnecessary. We also use MySQL, Redis, and NGINX. Plus, we have a lot of other cool stuff. We have MongoDB, rabbits running around, we have all kinds of things \u2014 but that\u2019s not my area, and I don\u2019t deal with it.<\/p>\n<h1>OpenResty<\/h1>\n<p>\nI've talked about myself. Let's dive into what I will be discussing today:<\/p>\n<ul>\n<li>What is OpenResty and how is it used?<\/li>\n<li>Why reinvent the wheel when we already have Python, NodeJS, PHP, Go, and other great tools that everyone is happy with?<\/li>\n<li>And a few real-life examples. I had to significantly cut down my presentation because it was initially about 3.5 hours long, so there will be few examples.<\/li>\n<\/ul>\n<p>\nOpenResty is NGINX. Thanks to it, we have a fully functional web server that's well-written and operates quickly. I believe most of us use NGINX in production. You all know it's fast and great. It features excellent synchronous I\/O, so we don't need to reinvent the wheel like we did with the gevent library in Python. Gevent is cool, but if you write some C code and something goes wrong, debugging with gevent can drive you insane. I had an experience: it took me two whole days to figure out what went wrong. If someone hadn't spent weeks digging into it, found the problem, and posted it online, which Google then discovered, we would have gone completely mad.<\/p>\n<p>NGINX already includes caching and static content handling. You don\u2019t have to worry about how to set it up correctly so that nothing gets sluggish and you don't lose any descriptors. NGINX is easy to deploy; you don\u2019t have to think about what to use\u2014WSGI, PHP-FPM, Gunicorn, Unicorn. You set up NGINX, hand it over to the admins, and they know how to work with it. NGINX processes requests in a structured manner. I'll talk a bit more about that later. In short, it has a phase when it first receives the request, when it processes it, and when it delivers the content to the user.<\/p>\n<p>NGINX is awesome, but there is one problem: it\u2019s not flexible enough even with all the great features the team has crammed into the config, despite the customization options. This power is lacking. That's why the team at Taobao embedded Lua into it about eight years ago. What does that provide?<\/p>\n<ul>\n<li><strong>Size<\/strong>. It's lightweight. LuaJIT adds around 100-200 kilobytes of memory overhead with minimal performance overhead.<\/li>\n<li><strong>Speed<\/strong>The LuaJIT interpreter is close to C in many situations, sometimes it falls behind Java, and in some cases, it surpasses it. For a while, it was considered state of the art, the best JIT compiler. Now, there are more advanced ones, but they are quite heavy, like V8. Some JS interpreters and the Java HotSpot are faster in some cases, but still lose out in others.<\/li>\n<li><strong>Ease of learning<\/strong>. If, for instance, you have a codebase in Perl, and you are not Booking, you won\u2019t find Perl programmers. Because they are not available; they've all been taken, and teaching them is long and complicated. If you want programmers in something else, you might also have to retrain them or find some. With Lua, it\u2019s simple. Any junior can learn Lua in three days. It took me about two hours to get acclimated. After two hours, I was already writing production code. Within a week, it was deployed to production.<\/li>\n<\/ul>\n<p>\nAs a result, it looks like this:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/1e6c253c5436fdc894f8be7999799cb0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nThere\u2019s a lot going on here. OpenResty has gathered a bunch of modules, both Lua-based and engine-based. And everything is ready for you \u2014 deploy it and it works.<\/p>\n<h1>Examples<\/h1>\n<p>\nEnough of the theory, let's move on to the code. Here\u2019s a simple Hello World:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/bbd056b72c71b193b0f06dd3248f5381.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWhat do we have here? This is the engine\u2019s location. We don\u2019t worry about writing our own routing, nor do we take any pre-made one \u2014 we already have it in NGINX, and we\u2019re living well and lazily.<\/p>\n<p><code>content_by_lua_block<\/code> is a block that tells us that we are delivering content using a Lua script. We take the engine variable <code>remote_addr<\/code> and pass it to <code>string.format<\/code>. This is the same as <code>sprintf<\/code>, but in Lua, and it\u2019s correct. And we send it to the client.<\/p>\n<p>As a result, it will look like this:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/9f1aaf6625f1fe5904b1e8a568fac76d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nBut let's return to the real world. In production, no one deploys Hello World. Our applications usually interact with a database or something else, and most of the time, they wait for a response.<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/485f713c0284e16b0817500c8606c104.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIt just sits and waits. This isn\u2019t very good. When 100,000 users come in, it becomes quite difficult. So, let's create a simple application as an example. We\u2019ll be looking for pictures, for instance, of kittens. But we won\u2019t just look randomly, we\u2019ll expand the keywords and, if a user searches for \"kittens\", we\u2019ll find them cats, fluffballs, and more. First, we need to get the request data on the backend. Here\u2019s what it looks like:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/a2134f86f15764745ae8330f63185367.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nTwo lines allow you to retrieve GET parameters, no complexities. Then, we can obtain this information from a database with a table by keyword and extension through a regular SQL query. It's straightforward. It looks like this:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/4543685dc907f30bba2a079a0fadad2c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe connect the library <code>resty.mysql<\/code>, which we already have included. We don't need to install anything, everything is ready. We specify how to connect and make the SQL query:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/2234b3a5b2e1d8efafec00a49f1a13b0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nThere's a bit of a scare here, but everything works. Here, 10 is the limit. We are retrieving 10 records; we're lazy and don't want to show more. I forgot about the limit in SQL.<\/p>\n<p>Next, we find images for all the queries. We gather a bunch of queries and populate a Lua table called <code>reqs<\/code>, and then we do <code>ngx.location.capture_multi<\/code>.<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/c18171845b3bd3872c4a7a7feae0d4bc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAll these requests go in parallel, and we receive the responses back. The execution time equals the response time of the slowest one. If all of them respond in 50 milliseconds and we sent a hundred queries, the response will come back in 50 milliseconds.<\/p>\n<p>Since we're lazy and don't want to write HTTP processing and caching, we'll make NGINX do everything for us. As you saw, there was a request to <code>url\/fetch<\/code>, here it is:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/ef8fcc6905b2860a7f214c41251582a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nWe make a simple <code>proxy_pass<\/code>, specify where to cache, how to do it, and it all works.<\/p>\n<p>But that's not enough; we also need to return data to the user. The simplest idea is to serialize everything in JSON, easy enough in two lines. We set the Content-Type and return JSON.<\/p>\n<p>But there\u2019s one complication: the user doesn\u2019t want to read JSON. We need to involve frontend developers. Sometimes we don\u2019t want to do this at first. And SEO specialists will say that if we're searching for images, they don\u2019t care. But if we're giving them some content, they\u2019ll say that search engines are indexing nothing.<\/p>\n<p>What to do about this? Naturally, we will return HTML to the user. Generating it manually is not practical, so we want to use templates. For this, there is a library <code>lua-resty-template<\/code>.<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/66a6cffc402575d286cb00d138dc201a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nYou probably saw the three scary letters OPM. OpenResty comes with its own package manager, through which you can install a bunch of different modules, in particular, <code>lua-resty-template<\/code>. This is a simple template engine, similar to Django templates. You can write code there and make substitutions for variables.<\/p>\n<p>As a result, everything will look something like this:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/b54497e4f1ab5a80183dc49c172a7f15.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nWe took the data and rendered the template again in two lines. The user is happy; they received kittens. Since we expanded the query, they also got a sea otter along with the kittens. Who knows, maybe that\u2019s what they were actually looking for but couldn\u2019t articulate their request properly.<\/p>\n<p>Everything is great, but we are in development, and we don't want to show this to users yet. Let's implement authentication. To do this, let's see how NGINX processes requests in terms of OpenResty:<\/p>\n<ul>\n<li>The first phase \u2014 <strong>access<\/strong>, when the user just arrived, and we looked at them based on headers, IP address, and other data. We can immediately block them if they don't seem suitable. This can be used for authentication, or if we receive a high volume of requests, we can easily cut them off at this phase.<\/li>\n<li><strong>rewrite<\/strong>. We rewrite some request data.<\/li>\n<li><strong>content<\/strong>. We deliver content to the user.<\/li>\n<li><strong>headers filter<\/strong>. We modify the response headers. If we used <code>proxy_pass<\/code>, we can rewrite some headers before delivering them to the user.<\/li>\n<li><strong>body filter<\/strong>. We can modify the body.<\/li>\n<li><strong>log<\/strong>\u00a0\u2014 logging. We can write logs to Elasticsearch without an additional layer.<\/li>\n<\/ul>\n<p>\nOur authentication will look something like this:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/f6c16665b75ce0fa0ee69e07ab6a4a61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nWe will add this to the <code>location<\/code>, which we described earlier, and insert the following code:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/126d8411c92afa92f3c4f5b9791b3e9c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nWe check if we have a cookie token. If not, we redirect to authentication. Users are clever and might guess they need to set a cookie token. Therefore, we will also store it in Redis:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/b876372412d648885c2f7d53e712a85b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nThe code for working with Redis is very simple and doesn\u2019t differ from other languages. The input\/output is non-blocking, both there and here. If you write synchronous code, it works asynchronously. It\u2019s somewhat like using gevent, but done well.<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/74066c9c750c718f368617faacbe0acc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLet\u2019s create the authentication itself:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/0b3b486ca3c417716ebdaac189bfdcbf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nWe state that we need to read the request body. We get the POST arguments and check if the username and password are correct. If they are incorrect, we redirect to authentication. If they are correct, we store the token in Redis:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/bcf470d84791b6d1d01152d5ad511dbd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nDon't forget to set the cookie; this is done in just two lines:<\/p>\n<p><img decoding=\"async\" alt=\"OpenResty: Transforming NGINX into a Full-Fledged Application Server\" src=\"\/wp-content\/uploads\/2020\/02\/efe06a113de28bacd14b26d6bb62a037.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThis is a simple, theoretical example. We certainly won't create a service that shows people kittens. But who knows. So let's go over what can be done in production.<\/p>\n<ul>\n<li><strong>Minimalist backend<\/strong>. Sometimes we need to output just a little bit of data on the backend: sometimes we need to insert a date, display a list, indicate how many users are currently on the site, attach a counter, or show some statistics. Something small like that. Minimal pieces can be done very easily. This will turn out quickly, easily, and great.\n<\/li>\n<li><strong>Data Preprocessing<\/strong>. Sometimes we want to embed advertisements into our web page, and we fetch these ads using API requests. This can be done very easily here. We do not overload our backend, which is already working hard. We can gather and assemble things here. We can combine some JS or, conversely, break apart something, preprocess it before sending it to the user.\n<\/li>\n<li><strong>Facade for Microservices<\/strong>. This is also a very good case, which I have implemented. Before this, I worked at Tenzor, a company that deals with electronic reporting, providing reporting for about half of the legal entities in the country. We created a service where many things were done with this same mechanism: routing, authorization, and more.<br \/>\nOpenResty can be used as glue for your microservices, providing a unified access point and interface for everything. Since microservices can be written in different languages, such as Node.js, PHP, Python, and there may be some piece running on Erlang, we understand we don\u2019t want to rewrite the same code everywhere. Therefore, OpenResty can be implemented on the front end.<\/p>\n<\/li>\n<li><strong>Statistics and Analytics<\/strong>. Usually, NGINX is placed at the entry point, and all requests pass through it. It is very convenient to gather here. We can calculate something immediately and send it somewhere, for example, to Elasticsearch, Logstash, or simply record it in a log and then send it somewhere.\n<\/li>\n<li><strong>Multiplayer Systems<\/strong>. For example, online games can also be done very well. Today in Cape Town, Alexander Gladys will talk about how to quickly prototype a multiplayer game using OpenResty.\n<\/li>\n<li><strong>Request Filtering (WAF)<\/strong>. Nowadays, it's trendy to create various web application firewalls, and there are many services that provide them. With OpenResty, you can create a web application firewall that easily filters requests according to your requirements. If you're using Python, you know that PHP won't be injected at all, unless, of course, you spawn it from the console somewhere. You know you have MySQL and Python. There may be attempts at directory traversal and trying to inject something into the database. Therefore, you can quickly and cheaply filter out suspicious requests right at the front.\n<\/li>\n<li><strong>Community.<\/strong> Since OpenResty is built on NGINX, it has a bonus \u2014 which is <strong>the NGINX community.<\/strong>It is quite large, and a considerable portion of the questions you will encounter initially has already been addressed by the NGINX community.\n<p><strong>Lua developers<\/strong>. Yesterday, I talked with some guys who came to the HighLoad++ training day and heard that only Tarantool is written in Lua. That's not true; many things are made with Lua. Examples include: OpenResty, the XMPP server Prosody, the game engine Love2D, and Lua is scripted in Warcraft and other places. There are many Lua developers, and they have a large and responsive community. All of my questions about Lua were solved within a few hours. When you write to the mailing list, literally within minutes there are plenty of responses explaining what and how, connecting the dots. It's really great. Unfortunately, not everywhere is there such a kind and friendly community.<br \/>\nThere is a GitHub page for OpenResty where you can open an issue if something breaks. There is a mailing list on Google Groups where you can discuss general issues, and there's a mailing list in Chinese\u2014just in case you don't speak English but have knowledge of Chinese.<\/li>\n<\/ul>\n<p><\/p>\n<h1>Summary<\/h1>\n<p><\/p>\n<ul>\n<li>I hope I've conveyed that OpenResty is a very convenient framework focused on the web.<\/li>\n<li>It has a low entry barrier since the code resembles what we write, and the language is quite simple and minimalist.<\/li>\n<li>It provides asynchronous I\/O without callbacks, so we won't have the spaghetti code that we can sometimes end up with in NodeJS.<\/li>\n<li>It has an easy deployment since we only need NGINX with the required module and our code, and it all works right away.<\/li>\n<li>A large and responsive community.<\/li>\n<\/ul>\n<p>\nI didn't go into detail about how routing is done; it would have turned into a very long story.<\/p>\n<p>Thank you for your attention!<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"silrEB0Brvo\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/silrEB0Brvo\/hqdefault.jpg\" alt=\"Play video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\n<em><noindex><a rel=\"nofollow\" href=\"http:\/\/www.highload.ru\/2016\/abstracts\/2432.html\">Vladimir Protasov - OpenResty: turning NGINX into a full-fledged application server<\/a><\/noindex><\/em><br \/>\n<br \/>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/321864\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041c\u044b \u0432\u043d\u043e\u0432\u044c \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0443 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0441 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 HighLoad++ 2016, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043b\u0430 \u0432 \u043f\u043e\u0434\u043c\u043e\u0441\u043a\u043e\u0432\u043d\u043e\u043c \u0421\u043a\u043e\u043b\u043a\u043e\u0432\u043e 7\u20148 \u043d\u043e\u044f\u0431\u0440\u044f \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430. \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u041f\u0440\u043e\u0442\u0430\u0441\u043e\u0432 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043a\u0430\u043a \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c NGINX \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e OpenResty \u0438 Lua. \u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u041f\u0440\u043e\u0442\u0430\u0441\u043e\u0432, \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0432 Parallels. \u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0447\u0443\u0442\u044c-\u0447\u0443\u0442\u044c \u043e \u0441\u0435\u0431\u0435. \u0422\u0440\u0438 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0438 \u0441\u0432\u043e\u0435\u0439 \u0436\u0438\u0437\u043d\u0438 \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c \u0442\u0435\u043c, \u0447\u0442\u043e \u043f\u0438\u0448\u0443 \u043a\u043e\u0434. \u0421\u0442\u0430\u043b [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":71379,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-71378","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041c\u044b \u0432\u043d\u043e\u0432\u044c \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0443.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47OpenResty: \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c NGINX \u0432 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041c\u044b \u0432\u043d\u043e\u0432\u044c \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0443.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-02-25T17:45:02+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-03T13:14:21+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47OpenResty: Transforming NGINX into a Full-fledged Application Server | ProHoster","description":"We are once again publishing the transcript.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47OpenResty: \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c NGINX \u0432 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 | ProHoster","og:description":"\u041c\u044b \u0432\u043d\u043e\u0432\u044c \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0443.","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/openresty-prevrashhaem-nginx-v-polnoczennyj-server-prilozhenij","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-02-25T17:45:02+00:00","article:modified_time":"2020-03-03T13:14:21+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"71378","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:03:22","updated":"2022-09-30 08:39:30","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/71378","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=71378"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/71378\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/71379"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=71378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=71378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=71378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}