{"id":5695,"date":"2026-05-13T19:06:59","date_gmt":"2026-05-13T10:06:59","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=5695"},"modified":"2026-05-13T19:09:18","modified_gmt":"2026-05-13T10:09:18","slug":"webserver-miniwebserver-reverse-proxy-12","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/05\/13\/webserver-miniwebserver-reverse-proxy-12\/","title":{"rendered":"[Webserver]miniWebserver+Reverse Proxy-(12)"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc8fc\uc694 \ubcc0\uacbd\uc0ac\ud56d\uc740 \uc544\ub798\uc640 \uac19\uc2b5\ub2c8\ub2e4.<br>The major changes are as follows.<\/p>\n\n\n\n<p>\u2714\ufe0f \u2757\ufe0f \ud45c\uc2dc\ub41c \ubd80\ubd84\uc774 \ubcc0\uacbd\uc0ac\ud56d\uc785\ub2c8\ub2e4.<br>The parts marked with \u2757\ufe0f are the changes.<\/p>\n\n\n\n<p>\u2714\ufe0f \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc \uae30\ub2a5\uc744 \ucd94\uac00\ud588\uc2b5\ub2c8\ub2e4.<br>Added a reverse proxy feature.<\/p>\n\n\n\n<p>\u2714\ufe0f \ub098\uba38\uc9c0 \uc124\uba85\uc740 \ucf54\ub4dc \uc8fc\uc11d\uc744 \ucc38\uace0\ud558\uc138\uc694<br>Please refer to the code comments for the rest of the explanation.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb\ucf54\ub4dc \/ Code<\/p>\n\n\n\n<p>\u2714\ufe0f CMakeLists.txt<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \uc2e4\ud589 \ud30c\uc77c \uc0dd\uc131 \ub300\uc0c1 \uc18c\uc2a4 \ud30c\uc77c \ub098\uc5f4 \/ List source files to be used for creating executable files\nadd_executable(main\n    Main.cpp\n    Router.cpp\n    Server.cpp\n    HttpsServer.cpp \n    <strong>Proxy.cpp <\/strong>\/\/ \ud30c\uc77c\ucd94\uac00 \/ Added file\u2757\ufe0f\n)<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f Proxy.h<\/p>\n\n\n\n<p>&#8212; \ud30c\uc77c \ucd94\uac00 \/ Add file<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ifndef PROXY_H\n#define PROXY_H\n\n#include &lt;string&gt;\n\n\/\/ \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc \uc694\uccad \ud568\uc218 \uc120\uc5b8 \/ Declaration of reverse proxy request function\n\/\/ backend_ip: \ubc31\uc5d4\ub4dc \uc11c\ubc84 IP \uc8fc\uc18c \/ Backend server IP address,\n\/\/ backend_port: \ud3ec\ud2b8\ubc88\ud638 \/ port number\n\/\/ client_request: \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c \ubc1b\uc740 HTTP \uc694\uccad \uc804\uccb4 \ubb38\uc790\uc5f4 \/ The entire string of the HTTP request received from the client\n\/\/ \ubc18\ud658: \ubc31\uc5d4\ub4dc\ub85c\ubd80\ud130 \ubc1b\uc740 HTTP \uc751\ub2f5 \ubb38\uc790\uc5f4\n\/\/ Return: HTTP response string received from the backend\n\nstd::string forward_request_to_backend(const std::string&amp; backend_ip, int backend_port, const std::string&amp; client_request);\n\n#endif \/\/ PROXY_H<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f Proxy.cpp<\/p>\n\n\n\n<p>&#8212; \ud30c\uc77c \ucd94\uac00 \/ Add file<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include \"Proxy.h\"\n#include &lt;sys\/socket.h&gt;\n#include &lt;arpa\/inet.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;cstring&gt;\n#include &lt;chrono&gt;     \/\/ timeout\n#include &lt;fcntl.h&gt;\n\n\/\/ \uac04\ub2e8\ud55c timeout \uc124\uc815 \ud568\uc218\n\/\/ bool set_nonblocking(int sock) {\n\/\/     int flags = fcntl(sock, F_GETFL, 0);\n\/\/     return fcntl(sock, F_SETFL, flags | O_NONBLOCK) != -1;\n\/\/ }\n\nstd::string forward_request_to_backend(const std::string&amp; backend_ip,\n                                       int backend_port,\n                                       const std::string&amp; client_request) {\n\n    \/\/ IPV4\ub85c \uc18c\ucf13 \uc5f0\uacb0 \/ Socket connection via IPv4\n    int sock = socket(AF_INET, SOCK_STREAM, 0);\n    if (sock &lt; 0) {\n        return \"HTTP\/1.1 500 Internal Server Error\\r\\n\\r\\n\";\n    }\n\n    \/*\n    10\ucd08 connect timeout\n    - 10\uc740 \ucd08(seconds)\ub97c \uc758\ubbf8\ud558\uace0, 0\uc740 \ub9c8\uc774\ud06c\ub85c\ucd08(microseconds)\ub97c \uc758\ubbf8\ud569\ub2c8\ub2e4..\n    - setsockopt() \ud568\uc218\ub294 \uc18c\ucf13\uc758 \ub2e4\uc591\ud55c \uc635\uc158\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.\n    - SO_RCVTIMEO: \uc18c\ucf13\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc218\uc2e0\ud560 \ub54c \ucd5c\ub300 \ub300\uae30 \uc2dc\uac04\uc744 \uc124\uc815\ud558\ub294 \uc635\uc158\uc785\ub2c8\ub2e4.\n                   \uc989, 10\ucd08 \uc774\ub0b4\uc5d0 \ub370\uc774\ud130\uac00 \uc624\uc9c0 \uc54a\uc73c\uba74 \uc218\uc2e0 \ud568\uc218(recv \ub4f1)\uac00 \ud0c0\uc784\uc544\uc6c3\ub429\ub2c8\ub2e4.\n    - SO_SNDTIMEO: \ub370\uc774\ud130\ub97c \uc804\uc1a1\ud560 \ub54c \ucd5c\ub300 \ub300\uae30 \uc2dc\uac04\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4.\n                   10\ucd08 \uc774\ub0b4\uc5d0 \uc804\uc1a1\uc774 \ub418\uc9c0 \uc54a\uc73c\uba74 \ud0c0\uc784\uc544\uc6c3 \ucc98\ub9ac\ud569\ub2c8\ub2e4.\n\n    10 second connect timeout\n    - 10 represents seconds, and 0 represents microseconds.\n    - The setsockopt() function sets various options for a socket.\n    - SO_RCVTIMEO: This option sets the maximum waiting time when receiving data from a socket.\n                   In other words, if data does not arrive within 10 seconds, the receive function (such as recv) times out.\n    - SO_SNDTIMEO: Specifies the maximum waiting time when transmitting data.\n                   If transmission does not occur within 10 seconds, a timeout is triggered.\n   *\/\n    struct timeval tv = {10, 0};\n    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &amp;tv, sizeof(tv));\n    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &amp;tv, sizeof(tv));\n\n    sockaddr_in serv_addr{};\n    serv_addr.sin_family = AF_INET; \/\/IPV4\n    serv_addr.sin_port = htons(backend_port); \/\/ Host TO Network Short(big endian)\n\n    \/\/ inet_pton : \ud14d\uc2a4\ud2b8\ud615\uc2dd\uc744 \uc774\uc9c4 IP\uc8fc\uc18c\ub85c\ubcc0\ud658 \/ Convert text format to binary IP address\n    \/\/ backend_ip.c_str() : IP \ubb38\uc790\uc5f4 \/ IP string\n    \/\/ &amp;serv_addr.sin_addr) : \uc800\uc7a5\ub420 \uc704\uce58 \/ Location to be saved\n    \/\/\n    if (inet_pton(AF_INET, backend_ip.c_str(), &amp;serv_addr.sin_addr) &lt;= 0) {\n        close(sock);\n        return \"HTTP\/1.1 500 Internal Server Error\\r\\n\\r\\n\";\n    }\n\n    \/\/ \uc18c\ucf13\uc73c\ub85c \uc9c0\uc815\ub41c \uc8fc\uc18c\uc5d0 \uc811\uc18d\uc2dc\ub3c4 \uc2e4\ud328\uc2dc \uc624\ub958 \ubc18\ud658\n    \/\/ Returns an error if the attempt to connect to the address specified by the socket fails.\n    if (connect(sock, (struct sockaddr*)&amp;serv_addr, sizeof(serv_addr)) &lt; 0) {\n        close(sock);\n        return \"HTTP\/1.1 504 Gateway Timeout\\r\\n\\r\\n\";\n    }\n\n    \/\/ \uc804\uccb4 \ub370\uc774\ud130 \uc804\uc1a1 \ubcf4\uc7a5 \/ Full data transfer guaranteed\n    size_t total_sent = 0; \/\/ \uc804\uc1a1\ub41c \ubc14\uc774\ud2b8 \ub204\uc801 \/ Accumulation of transferred bytes\n\n    \/\/ \uc694\uccad \ud06c\uae30\ub9cc\ud07c \uc804\uc1a1 \ubc18\ubcf5 \/ Repeat transmission for the requested size\n    while (total_sent &lt; client_request.size()) {\n        \/\/ client_request.data() + total_sent\n        \/\/ total_sent\ub85c \ubcf4\ub0b8 \ub370\uc774\ud130\uc758 \ub2e4\uc74c \uba54\ubaa8\ub9ac \uc704\uce58\n        \/\/ Next memory location of the data sent with total_sent\n        \/\/\n        \/\/ \ub370\uc774\ud130 \uc804\uc1a1\uc774 \uc644\ub8cc\ub41c \uc704\uce58\uc5d0 \ucee4\uc11c\uac00 \uc788\uace0 \uc5ec\uae30\uc11c \ub2e4\uc2dc \ub370\uc774\ud130 \ud06c\uae30\ub9cc\ud07c \uc804\uc1a1\n        \/\/ The cursor is at the location where data transmission is complete,\n        \/\/ and from here, data of the size is transmitted again.\n        ssize_t sent = send(sock, client_request.data() + total_sent,\n                           client_request.size() - total_sent, 0);\n        if (sent &lt; 0) {\n            close(sock);\n            return \"HTTP\/1.1 502 Bad Gateway\\r\\n\\r\\n\";\n        }\n        total_sent += sent;\n    }\n\n    \/\/ \uc751\ub2f5 \uc218\uc2e0 \/ Receive response\n    \/\/ html\ud30c\uc77c \ub0b4\uc6a9 \uc77d\uc5b4\uc624\uae30 \/ Read HTML file content\n    char buffer&#91;8192];\n    std::string response;\n    response.reserve(65536);  \/\/ \ub300\ub7b5\uc801\uc778 \ucd08\uae30 \uc6a9\ub7c9\n\n    \/\/ \ubc18\ubcf5\uc801\uc73c\ub85c \ud55c\ubc88\uc5d0 8192\ub9cc\ud07c \ub370\uc774\ud130 \uc77d\uc5b4\uc640\uc11c response\ubcc0\uc218\uc5d0 \uc800\uc7a5\ud558\uae30\n    \/\/ Repeatedly read 8192 bytes of data at a time and store them in the response variable\n    ssize_t received;\n    while ((received = recv(sock, buffer, sizeof(buffer), 0)) &gt; 0) {\n        response.append(buffer, received);\n    }\n\n    close(sock);\n\n    if (received &lt; 0 &amp;&amp; response.empty()) {\n        return \"HTTP\/1.1 502 Bad Gateway\\r\\n\\r\\n\";\n    }\n\n    \/\/ \uc751\ub2f5\uc774 \uc544\uc608 \uc5c6\uc73c\uba74 \uc5d0\ub7ec\n    \/\/ Error handling if there is no response at all\n    if (response.empty()) {\n        return \"HTTP\/1.1 502 Bad Gateway\\r\\n\\r\\n\";\n    }\n\n    return response;\n}\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0fmain.cpp<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>        \/\/ \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc \uc801\uc6a9 \/ Apply reverse proxy\u2757\ufe0f\n        \/\/ \uac04\ub2e8\ud788 \/api\/ \uacbd\ub85c\ub97c \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc\ub85c \ud310\ub2e8\n        \/\/ Simply treat the \/api\/ path as a reverse proxy\n        if ((method == \"GET\" || method == \"POST\") &amp;&amp;\n            (path == \"\/api\" || path.find(\"\/api\/\") == 0)) {\n\n            std::string backend_ip = \"127.0.0.1\";\n            int backend_port = 8080;\n\n            std::string modified_req = req;\n\n            \/\/ \/api \u2192 \/ \ub85c \ubcc0\uacbd (\ubc31\uc5d4\ub4dc\uac00 \ub8e8\ud2b8 \uacbd\ub85c\ub85c \ubc1b\ub3c4\ub85d)\n            if (path == \"\/api\") {\n                size_t pos = modified_req.find(\" \/api \");\n                if (pos != std::string::npos) {\n                    modified_req.replace(pos, 5, \" \/\");\n                }\n            }\n            else if (path.find(\"\/api\/\") == 0) {\n                size_t pos = modified_req.find(\"\/api\/\");\n                if (pos != std::string::npos) {\n                    modified_req.replace(pos, 5, \"\/\");\n                }\n            }\n\n            \/\/ Host \ud5e4\ub354 \uc218\uc815 \/ Modify Host header\n            size_t host_pos = modified_req.find(\"\\r\\nHost:\");\n            if (host_pos == std::string::npos) {\n                host_pos = modified_req.find(\"\\r\\nhost:\");\n            }\n            if (host_pos != std::string::npos) {\n                size_t line_end = modified_req.find(\"\\r\\n\", host_pos + 1);\n                if (line_end != std::string::npos) {\n                    modified_req.replace(host_pos, line_end - host_pos, \"\\r\\nHost: 127.0.0.1:8080\");\n                }\n            }\n\n            \/\/ Connection: close\n            size_t conn_pos = modified_req.find(\"Connection:\");\n            if (conn_pos != std::string::npos) {\n                size_t line_end = modified_req.find(\"\\r\\n\", conn_pos);\n                if (line_end != std::string::npos) {\n                    modified_req.replace(conn_pos, line_end - conn_pos, \"Connection: close\");\n                }\n            }\n\n            return forward_request_to_backend(backend_ip, backend_port, modified_req);\n        }<\/code><\/pre>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ube4c\ub4dc \/ Build<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd build\ncmake ..\nmake<\/code><\/pre>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc2e4\ud589 \/ Run<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.\/main<\/code><\/pre>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ube0c\ub77c\uc6b0\uc800 \uc811\uc18d \/ Access Browser<\/p>\n\n\n\n<p>&#8212; \uc544\ub798\uc758 \uc8fc\uc18c\ub85c \uc811\uc18d\ud558\uba74 http:\/\/localhost:8080\/api \ub85c \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc\ub418\ub294 \uac83\uc744 \ud655\uc778 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>If you access the address below, you can verify that it is reverse proxyed to http:\/\/localhost:8080\/api.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;localhost:6443\/api\nhttp:\/\/localhost:5080\/api<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc8fc\uc694 \ubcc0\uacbd\uc0ac\ud56d\uc740 \uc544\ub798\uc640 \uac19\uc2b5\ub2c8\ub2e4.The major changes are as follows. \u2714\ufe0f \u2757\ufe0f \ud45c\uc2dc\ub41c \ubd80\ubd84\uc774 \ubcc0\uacbd\uc0ac\ud56d\uc785\ub2c8\ub2e4.The parts marked with \u2757\ufe0f are the changes. \u2714\ufe0f \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc \uae30\ub2a5\uc744 \ucd94\uac00\ud588\uc2b5\ub2c8\ub2e4.Added a reverse proxy feature. \u2714\ufe0f \ub098\uba38\uc9c0 \uc124\uba85\uc740 \ucf54\ub4dc \uc8fc\uc11d\uc744 \ucc38\uace0\ud558\uc138\uc694Please refer to the code comments for the rest of the explanation. \ud83d\udc49\ud83c\udffb\ucf54\ub4dc \/ Code \u2714\ufe0f CMakeLists.txt \u2714\ufe0f Proxy.h [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23,1],"tags":[],"class_list":["post-5695","post","type-post","status-publish","format-standard","hentry","category-cpp","category-uncategorized","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/5695","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=5695"}],"version-history":[{"count":2,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/5695\/revisions"}],"predecessor-version":[{"id":5698,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/5695\/revisions\/5698"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=5695"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=5695"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=5695"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}