[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