[Webserver]httplib webserver+reverse proxy(macoOS,Linux)

๐Ÿ‘‰๐Ÿป ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๋Š” ์›น์„œ๋ฒ„์— ๋“ค์–ด์˜จ ์š”์ฒญ์„ ๋‹ค๋ฅธ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
A reverse proxy is used to forward requests received by a web server to another server.

๐Ÿ‘‰๐Ÿป ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๊ฐ€ ์…‹ํŒ…๋œ ์„œ๋ฒ„http,https,5080)์™€ ์‹ค์ œ๋กœ ์‹คํ–‰๋  ์„œ๋ฒ„(http,3000)๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
Run the server with the reverse proxy set up (http,https,5080) and the server to be actually executed (http,3000).

๐Ÿ‘‰๐Ÿป ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋‹ค์Œ์ฒ˜๋Ÿผ 5080ํฌํŠธ๋กœ ์‹คํ–‰ํ•˜๋ฉด ํฌํŠธ3000๋ฒˆ์ธ ์„œ๋ฒ„์ •๋ณด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
If you run it on port 5080 in a browser as follows, you can view the server information on port 3000.

โœ”๏ธLinux : https://host.domain.org:5080/api

โœ”๏ธmacOS : http://localhost:5080/api

๐Ÿ‘‰๐Ÿป macOS์—์„œ๋Š” http์„œ๋ฒ„๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  Linux์„œ๋ฒ„์—์„œ๋Š” https์„œ๋ฒ„๋ฅผ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.
Test the HTTP server on macOS and the HTTPS server on Linux.


๐Ÿ‘‰๐Ÿป ๋ฐฉํ™”๋ฒฝ์—์„œ 3000๋ฒˆ ํฌํŠธ๋ฅผ ์ถ”๊ฐ€๋กœ ์˜คํ”ˆ ํ•ฉ๋‹ˆ๋‹ค.(iptables)
Open port 3000 additionally in the firewall (iptables).

$ sudo iptables -I INPUT -p tcp --dport 3000 -j ACCEPT
$ sudo netfilter-persistent save

๐Ÿ‘‰๐Ÿป ๋‚˜๋จธ์ง€ ๋ฐฉํ™”๋ฒฝ ์„ค์ • ๋ถ€๋ถ„ ์„ค๋ช…์€ ์ด์ „ ๊ฒŒ์‹œ๋ฌผ์„ ์ฐธ์กฐํ•˜์„ธ์š”
Please refer to the previous post for the explanation of the remaining firewall settings.

โœ”๏ธ httplib.h(0.42.0)

curl -L https://raw.githubusercontent.com/yhirose/cpp-httplib/master/httplib.h -o httplib.h

๐Ÿ‘‰๐ŸปHttp server(http_server.cpp)-Reverse proxy setting

โœ”๏ธ ์ฝ”๋“œ / Code

#include "httplib.h"
#include <iostream>

static void copy_response(const httplib::Result& r, httplib::Response& res) {
    if (!r) {
        res.status = 502;
        res.set_content("Backend server is unreachable.", "text/plain; charset=utf-8");
        return;
    }
    res.status = r->status;

    for (const auto& h : r->headers) {
        if (h.first == "Connection" || h.first == "Keep-Alive" ||
            h.first == "Proxy-Authenticate" || h.first == "Proxy-Authorization" ||
            h.first == "TE" || h.first == "Trailers" ||
            h.first == "Transfer-Encoding" || h.first == "Upgrade") {
            continue;
        }
        res.set_header(h.first.c_str(), h.second.c_str());
    }

    res.body = r->body;
}

int main() {
    httplib::Server svr;

    // /api ์™€ /api/... ๋ชจ๋‘ ์ฒ˜๋ฆฌ
    svr.Get(R"(/api.*)", [](const httplib::Request& req, httplib::Response& res) {
        std::cout << "Proxying: " << req.method << " " << req.path << "\n";

        httplib::Client cli("localhost", 3000);

        if (auto backend_res = cli.Get(req.path.c_str())) {
            copy_response(backend_res, res);
        } else {
            res.status = 502;
            res.set_content("Backend server is unreachable.", "text/plain; charset=utf-8");
        }
    });

    std::cout << "Proxy server listening on http://0.0.0.0:5080\n";
    svr.listen("0.0.0.0", 5080);

    return 0;
}

โœ”๏ธ ์ปดํŒŒ์ผ / Compiling

g++ -o http_server http_server.cpp -std=c++17 -pthread 

โœ”๏ธ ์‹คํ–‰ / Run

./http_server

๐Ÿ‘‰๐ŸปHttps server(https_server.cpp)-Reverse proxy setting

โœ”๏ธ ์ธ์ฆ์„œ ๋ณต์‚ฌ / Copy certificate

— ์ด์ „์— ๋ฐœ๊ธ‰๋ฐ›์€ Let’s Encrypt์ธ์ฆ์„œ์ž…๋‹ˆ๋‹ค.(์ด์ „ ๊ฒŒ์‹œ๋ฌผ ์ฐธ์กฐ)
Please refer to the previous post for the explanation of the remaining firewall settings.

$ sudo cp /etc/letsencrypt/live/host.domain.org/fullchain.pem ./
$ sudo cp /etc/letsencrypt/live/host.domain.org/privkey.pem ./

# ๋‚ด ๊ณ„์ •์œผ๋กœ ์†Œ์œ ๊ถŒ ๋ณ€๊ฒฝ / Change ownership to my account
$ sudo chown username:username *.pem  

โœ”๏ธ ์ฝ”๋“œ / Code

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"
#include <iostream>

static void copy_response(const httplib::Result& r, httplib::Response& res) {
    if (!r) {
        res.status = 502;
        res.set_content("Backend server is unreachable.", "text/plain; charset=utf-8");
        return;
    }
    res.status = r->status;


    for (const auto& h : r->headers) {
        if (h.first == "Connection" || h.first == "Keep-Alive" ||
            h.first == "Proxy-Authenticate" || h.first == "Proxy-Authorization" ||
            h.first == "TE" || h.first == "Trailers" ||
            h.first == "Transfer-Encoding" || h.first == "Upgrade") {
            continue;
        }
        res.set_header(h.first.c_str(), h.second.c_str());
    }

    res.body = r->body;
}

int main() {
    httplib::SSLServer svr("./fullchain.pem", "./privkey.pem");

    if (!svr.is_valid()) {
        std::cerr << "SSL server setup failed\n";
        return 1;
    }

    // ๋ชจ๋“  /api/... ์š”์ฒญ์„ ํ”„๋ก์‹œ ์ฒ˜๋ฆฌ
    svr.Get(R"(/api.*)", [](const httplib::Request& req, httplib::Response& res) {
        httplib::Client cli("localhost", 3000);

        if (auto backend_res = cli.Get(req.path.c_str())) {
            copy_response(backend_res, res);
        } else {
            res.status = 502;
            res.set_content("Backend server is unreachable.", "text/plain; charset=utf-8");
        }
    });

    std::cout << "Proxy server listening on https://0.0.0.0:5080\n";
    svr.listen("0.0.0.0", 5080);

    return 0;
}

โœ”๏ธ ์ปดํŒŒ์ผ / Compiling

g++ -o https_server https_server.cpp -std=c++17 -pthread -lssl -lcrypto

โœ”๏ธ ์‹คํ–‰ / Run

./https_server

๐Ÿ‘‰๐Ÿป http server(httplib_server.cpp)

โœ”๏ธ ์ฝ”๋“œ / Code

#include "httplib.h"
#include <iostream>

int main()
{
  httplib::Server svr;

  svr.Get("/",[](const httplib::Request &req, httplib::Response &res){
      res.set_content("<h1>Hi! silver hand!!!๐Ÿ‘‹</h1>", "text/html; charset=utf-8");
  });

  svr.Get("/api",[](const httplib::Request &req, httplib::Response &res){
   //res.set_content("Hello Red Dead Redemption!","text/plain");
   res.set_content("<h1>๐Ÿ‘‰๐ŸปHello Red Dead Redemption-reverse proxy ok!!</h1>", "text/html; charset=utf-8");
  });

  std::cout << "cpp-httplib server listening on http://localhost:3000" << std::endl;
  svr.listen("0.0.0.0", 3000);

  return 0;
}

โœ”๏ธ ์ปดํŒŒ์ผ / Compiling

g++ -o https_server https_server.cpp -std=c++17

โœ”๏ธ ์‹คํ–‰ / Run

./httplib_server

๐Ÿ‘‰๐Ÿป ์„œ๋ฒ„ ์‹คํ–‰ ๋ฐฉ๋ฒ• / How to run the server

โœ”๏ธ ์œ„์—์„œ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
You can test the code written above as follows.

โœ”๏ธ macOS

— 5080์„œ๋ฒ„์™€ 3000๋ฒˆ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
Run server 5080 and server 3000.

๋กœ์ปฌ ํ„ฐ๋ฏธ๋„ / local terminal

— ๋ธŒ๋ผ์šฐ์ €์—์„œ 5080ํฌํŠธ์„œ๋ฒ„๋กœ ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค. / Connect to the server on port 5080 in your browser.
(http://localhost:5080/api)

๋กœ์ปฌ๋ธŒ๋ผ์šฐ์ € / local browser

โœ”๏ธ Linux

— 5080์„œ๋ฒ„์™€ 3000๋ฒˆ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
Run server 5080 and server 3000.

๋ฆฌ๋ˆ…์Šค์„œ๋ฒ„ ํ„ฐ๋ฏธ๋„ / Linux Server Terminal

— ๋ธŒ๋ผ์šฐ์ €์—์„œ 5080ํฌํŠธ์„œ๋ฒ„๋กœ ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค. / Connect to the server on port 5080 in your browser.
(https://host.domain.org:5080/api)

๋ฆฌ๋ˆ…์Šค ์„œ๋ฒ„ ํ„ฐ๋ฏธ๋„ / Linux Server Terminal

Leave a Reply