fbi-proxy 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  FBI-Proxy provides easy HTTPS access to your local services with intelligent domain routing.
4
4
 
5
+ ## Features
6
+
7
+ ### Current Features ✅
8
+
9
+ - **Intelligent Domain Routing**: Multiple routing patterns for flexible service access
10
+ - Port-based routing (e.g., `3000.fbi.com` → `localhost:3000`)
11
+ - Host--Port routing (e.g., `api--3001.fbi.com` → `api:3001`)
12
+ - Subdomain routing with Host headers (e.g., `admin.app.fbi.com` → `app:80`)
13
+ - Direct host forwarding (e.g., `myserver.fbi.com` → `myserver:80`)
14
+ - **WebSocket Support**: Full WebSocket connection support for all routing patterns
15
+ - **High Performance**: Built with Rust for optimal performance and low resource usage
16
+ - **Easy Setup**: Simple one-command installation and startup
17
+ - **Docker Support**: Available as a Docker image for containerized deployments
18
+ - **Flexible Configuration**: Environment variables and CLI options for customization
19
+ - **Cross-Platform**: Works on macOS, Linux, and Windows
20
+ - **Integration Ready**: Compatible with reverse proxies like Caddy for HTTPS
21
+
22
+ ## Roadmap
23
+
24
+ ### Next Up 🚧
25
+ - [ ] **Configuration File Support** - YAML/JSON config for persistent routing rules
26
+ - [ ] **Access Control** - Domain filtering, host/port whitelisting
27
+ - [ ] **Request Logging** - Basic access logs for debugging
28
+ - [ ] **Health Checks** - Simple upstream service availability monitoring
29
+
30
+ ### Future Improvements 🔮
31
+ - [ ] **Load Balancing** - Round-robin between multiple upstream targets
32
+ - [ ] **Metrics** - Basic statistics (requests, response times, errors)
33
+ - [ ] **Hot Reload** - Update configuration without restart
34
+ - [ ] **Custom Headers** - Add/modify headers for specific routes
35
+
5
36
  ## Routing Examples
6
37
 
7
38
  ```bash
@@ -32,13 +63,53 @@ bunx fbi-proxy
32
63
  # expose to LAN
33
64
  bunx fbi-proxy --host 0.0.0.0 --port=2432
34
65
 
35
- # with caddy, forwarding *.fbi.com
36
- bunx fbi-proxy --caddy=fbi.com
66
+ # run with docker
67
+ docker run --rm --name fbi-proxy --network=host snomiao/fbi-proxy
68
+ ```
69
+
70
+ ## Using with Caddy (Optional)
71
+
72
+ FBI-Proxy focuses on the core proxy functionality. For HTTPS and advanced routing, you can use Caddy as a reverse proxy:
73
+
74
+ ### Install Caddy
37
75
 
38
- # run with docker, forwarding *.your-domain.com to host.
39
- docker run --rm --name fbi-proxy --network=host -v caddy_data:/etc/caddy/data snomiao/fbi-proxy --reverse-proxy=your-domain.com
76
+ ```bash
77
+ # macOS
78
+ brew install caddy
79
+
80
+ # Ubuntu/Debian
81
+ sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
82
+ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
83
+ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
84
+ sudo apt update
85
+ sudo apt install caddy
86
+
87
+ # Or download from https://caddyserver.com/download
40
88
  ```
41
89
 
90
+ ### Caddyfile Example
91
+
92
+ Create a `Caddyfile` to route `*.fbi.com` to FBI-Proxy:
93
+
94
+ ```caddyfile
95
+ *.fbi.com {
96
+ reverse_proxy localhost:2432
97
+ tls internal
98
+ }
99
+ ```
100
+
101
+ ### Run Both Services
102
+
103
+ ```bash
104
+ # Terminal 1: Start FBI-Proxy
105
+ bunx fbi-proxy
106
+
107
+ # Terminal 2: Start Caddy
108
+ caddy run --config Caddyfile
109
+ ```
110
+
111
+ Now you can access your services via HTTPS at `https://*.fbi.com`!
112
+
42
113
  ## Development
43
114
 
44
115
  ```bash
@@ -56,7 +127,6 @@ bun run build && bun run start
56
127
 
57
128
  - **Bun**: https://bun.sh/
58
129
  - **Rust**: https://rustup.rs/
59
- - **Caddy**: Auto-downloaded if not found
60
130
 
61
131
  ### Configuration
62
132
 
package/dist/cli.js CHANGED
@@ -4989,6 +4989,7 @@ var yargs_default = Yargs;
4989
4989
 
4990
4990
  // ts/buildFbiProxy.ts
4991
4991
  import { existsSync } from "fs";
4992
+ import { chmod } from "fs/promises";
4992
4993
 
4993
4994
  // ts/getProxyFilename.ts
4994
4995
  function getFbiProxyFilename() {
@@ -5124,13 +5125,18 @@ async function getFbiProxyBinary({ rebuild = false } = {}) {
5124
5125
  const release = "./release/" + binaryName;
5125
5126
  const built = `./target/release/fbi-proxy${isWin ? ".exe" : ""}`;
5126
5127
  if (!rebuild && existsSync(built)) {
5128
+ await chmod(built, 493).catch(() => {});
5127
5129
  return built;
5128
5130
  }
5129
- if (!rebuild && existsSync(release))
5131
+ if (!rebuild && existsSync(release)) {
5132
+ await chmod(release, 493).catch(() => {});
5130
5133
  return release;
5134
+ }
5131
5135
  await $`cargo build --release`;
5132
- if (existsSync(built))
5136
+ if (existsSync(built)) {
5137
+ await chmod(built, 493).catch(() => {});
5133
5138
  return built;
5139
+ }
5134
5140
  throw new Error("Oops, failed to build fbi-proxy binary. Please check your Rust setup.");
5135
5141
  }
5136
5142
 
@@ -5217,37 +5223,15 @@ var $2 = Object.assign(dSpawn2(), {
5217
5223
  cwd: (path) => dSpawn2({ cwd: path })
5218
5224
  });
5219
5225
 
5220
- // ts/downloadCaddy.ts
5221
- import { existsSync as existsSync2 } from "fs";
5222
- if (false) {}
5223
- async function downloadCaddy() {
5224
- const pwdCaddy = "./node_modules/.bin/caddy";
5225
- if (existsSync2(pwdCaddy))
5226
- return pwdCaddy;
5227
- if (await $`caddy --version`.catch(() => false)) {
5228
- return "caddy";
5229
- }
5230
- throw new Error("Failed to download Caddy. Please install Caddy manually or check your network connection.");
5231
- }
5232
-
5233
5226
  // ts/cli.ts
5234
5227
  process.chdir(path.resolve(import.meta.dir, ".."));
5235
- var argv = await yargs_default(hideBin(process.argv)).option("fbihost", {
5236
- type: "string",
5237
- default: "fbi.com",
5238
- description: "Set the FBI host"
5239
- }).option("caddy", {
5240
- type: "boolean",
5241
- default: false,
5242
- description: "Start Caddy server"
5243
- }).option("dev", {
5228
+ await yargs_default(hideBin(process.argv)).option("dev", {
5244
5229
  alias: "d",
5245
5230
  type: "boolean",
5246
5231
  default: false,
5247
5232
  description: "Run in development mode"
5248
5233
  }).help().argv;
5249
5234
  console.log("Preparing Binaries");
5250
- var FBIHOST = argv.fbihost;
5251
5235
  var FBIPROXY_PORT = String(await getPorts({ port: 2432 }));
5252
5236
  var proxyProcess = await hotMemo(async () => {
5253
5237
  const proxy = await getFbiProxyBinary();
@@ -5264,35 +5248,12 @@ var proxyProcess = await hotMemo(async () => {
5264
5248
  });
5265
5249
  return p;
5266
5250
  });
5267
- var caddyProcess = null;
5268
- if (argv.caddy) {
5269
- const caddy = await downloadCaddy();
5270
- caddyProcess = await hotMemo(async () => {
5271
- const p = $2.opt({
5272
- env: {
5273
- ...process.env,
5274
- FBIPROXY_PORT,
5275
- FBIHOST
5276
- }
5277
- })`${caddy} run`.process;
5278
- p.on("exit", (code) => {
5279
- console.log(`Caddy exited with code ${code}`);
5280
- process.exit(code || 0);
5281
- });
5282
- return p;
5283
- });
5284
- }
5285
5251
  console.log("All services started successfully!");
5286
5252
  console.log(`Proxy server PID: ${proxyProcess.pid}`);
5287
- if (caddyProcess) {
5288
- console.log(`Caddy server PID: ${caddyProcess.pid}`);
5289
- } else {
5290
- console.log("Caddy server not started (use --caddy to start it)");
5291
- }
5253
+ console.log(`Proxy server running on port: ${FBIPROXY_PORT}`);
5292
5254
  var exit = () => {
5293
5255
  console.log("Shutting down...");
5294
5256
  proxyProcess?.kill?.();
5295
- caddyProcess?.kill?.();
5296
5257
  process.exit(0);
5297
5258
  };
5298
5259
  process.on("SIGINT", exit);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fbi-proxy",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "FBI-Proxy provides easy HTTPS access to your local services with intelligent domain routing",
5
5
  "keywords": [
6
6
  "development-tools",
@@ -24,7 +24,6 @@
24
24
  "fbi-proxy": "dist/cli.js"
25
25
  },
26
26
  "files": [
27
- "Caddyfile",
28
27
  "dist",
29
28
  "release",
30
29
  "rs",
@@ -75,7 +74,5 @@
75
74
  "bun --bun prettier --write"
76
75
  ]
77
76
  },
78
- "trustedDependencies": [
79
- "@radically-straightforward/caddy"
80
- ]
77
+ "trustedDependencies": []
81
78
  }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/rs/fbi-proxy.rs CHANGED
@@ -1,20 +1,27 @@
1
1
  use clap::{Arg, Command};
2
2
  use futures_util::{SinkExt, StreamExt};
3
+ use http_body_util::{BodyExt, Full};
4
+ use hyper::body::{Bytes, Incoming};
3
5
  use hyper::header::{HeaderValue, HOST};
4
- use hyper::service::{make_service_fn, service_fn};
5
- use hyper::{Body, Client, Request, Response, Server, StatusCode, Uri};
6
+ use hyper::server::conn::http1;
7
+ use hyper::service::service_fn;
8
+ use hyper::{Request, Response, StatusCode, Uri};
6
9
  use hyper_tungstenite::{HyperWebsocket, WebSocketStream};
10
+ use hyper_util::client::legacy::{Client, connect::HttpConnector};
11
+ use hyper_util::rt::TokioIo;
7
12
  use log::{error, info};
8
13
  use regex::Regex;
9
14
  use std::convert::Infallible;
10
15
  use std::net::SocketAddr;
11
16
  use std::sync::Arc;
17
+ use tokio::net::TcpListener;
12
18
  use tokio_tungstenite::connect_async;
13
19
 
14
20
  type BoxError = Box<dyn std::error::Error + Send + Sync>;
21
+ type BoxBody = http_body_util::combinators::BoxBody<Bytes, hyper::Error>;
15
22
 
16
23
  pub struct FBIProxy {
17
- client: Client<hyper::client::HttpConnector>,
24
+ client: Client<HttpConnector, BoxBody>,
18
25
  number_regex: Regex,
19
26
  domain_filter: Option<String>,
20
27
  }
@@ -51,8 +58,12 @@ for subdomains
51
58
  */
52
59
  impl FBIProxy {
53
60
  pub fn new(domain_filter: Option<String>) -> Self {
61
+ let connector = HttpConnector::new();
62
+ let client = Client::builder(hyper_util::rt::TokioExecutor::new())
63
+ .build(connector);
64
+
54
65
  Self {
55
- client: Client::new(),
66
+ client,
56
67
  number_regex: Regex::new(r"^\d+$").unwrap(),
57
68
  domain_filter,
58
69
  }
@@ -131,7 +142,7 @@ impl FBIProxy {
131
142
  Some((format!("{}:80", host), host.to_string()))
132
143
  }
133
144
 
134
- pub async fn handle_request(&self, mut req: Request<Body>) -> Result<Response<Body>, BoxError> {
145
+ pub async fn handle_request(&self, req: Request<Incoming>) -> Result<Response<BoxBody>, BoxError> {
135
146
  // Extract host from headers and process according to rules
136
147
  let host_header = req
137
148
  .headers()
@@ -157,7 +168,7 @@ impl FBIProxy {
157
168
  );
158
169
  return Ok(Response::builder()
159
170
  .status(StatusCode::BAD_GATEWAY)
160
- .body(Body::from("Bad Gateway: Host not allowed"))?);
171
+ .body(Full::new(Bytes::from("Bad Gateway: Host not allowed")).map_err(|e| match e {}).boxed())?);
161
172
  }
162
173
  };
163
174
 
@@ -180,17 +191,22 @@ impl FBIProxy {
180
191
  );
181
192
  let target_uri: Uri = target_url.parse()?;
182
193
 
194
+ // Convert incoming body to a format the client can use
195
+ let (mut parts, incoming_body) = req.into_parts();
196
+ let body = incoming_body.map_err(|e| e).boxed();
197
+
183
198
  // Update request URI and headers
184
- *req.uri_mut() = target_uri;
185
- req.headers_mut()
186
- .insert(HOST, HeaderValue::from_str(&new_host)?);
187
- req.headers_mut().remove("content-encoding");
199
+ parts.uri = target_uri;
200
+ parts.headers.insert(HOST, HeaderValue::from_str(&new_host)?);
201
+ // Preserve content-encoding header to maintain compression
202
+
203
+ // Rebuild the request with the converted body
204
+ let new_req = Request::from_parts(parts, body);
188
205
 
189
206
  // Forward the request
190
- match self.client.request(req).await {
191
- Ok(mut response) => {
192
- // Remove content-encoding header from response
193
- response.headers_mut().remove("content-encoding");
207
+ match self.client.request(new_req).await {
208
+ Ok(response) => {
209
+ // Preserve content-encoding header in response to maintain compression
194
210
  let status = response.status();
195
211
  info!(
196
212
  "{} {}@{}{} {}",
@@ -200,7 +216,10 @@ impl FBIProxy {
200
216
  original_uri,
201
217
  status.as_u16()
202
218
  );
203
- Ok(response)
219
+ // Convert the response body back to BoxBody
220
+ let (parts, body) = response.into_parts();
221
+ let boxed_body = body.map_err(|e| e).boxed();
222
+ Ok(Response::from_parts(parts, boxed_body))
204
223
  }
205
224
  Err(e) => {
206
225
  error!(
@@ -213,17 +232,17 @@ impl FBIProxy {
213
232
  );
214
233
  Ok(Response::builder()
215
234
  .status(StatusCode::BAD_GATEWAY)
216
- .body(Body::from("FBIPROXY ERROR"))?)
235
+ .body(Full::new(Bytes::from("FBIPROXY ERROR")).map_err(|e| match e {}).boxed())?)
217
236
  }
218
237
  }
219
238
  }
220
239
 
221
240
  async fn handle_websocket_upgrade(
222
241
  &self,
223
- req: Request<Body>,
242
+ req: Request<Incoming>,
224
243
  target_host: &str,
225
244
  _new_host: &str, // Currently not used for WebSocket connections, but kept for consistency
226
- ) -> Result<Response<Body>, BoxError> {
245
+ ) -> Result<Response<BoxBody>, BoxError> {
227
246
  let uri = req.uri().clone();
228
247
  let ws_url = format!(
229
248
  "ws://{}{}",
@@ -241,7 +260,7 @@ impl FBIProxy {
241
260
  error!("WS :ws:{} => :ws:{}{} 502 ({})", target_host, target_host, uri, e);
242
261
  return Ok(Response::builder()
243
262
  .status(StatusCode::BAD_GATEWAY)
244
- .body(Body::from("WebSocket connection failed"))?);
263
+ .body(Full::new(Bytes::from("WebSocket connection failed")).map_err(|e| match e {}).boxed())?);
245
264
  }
246
265
  };
247
266
 
@@ -254,7 +273,9 @@ impl FBIProxy {
254
273
  });
255
274
 
256
275
  info!("WS :ws:{} => :ws:{}{} 101", target_host, target_host, uri);
257
- Ok(response)
276
+ let (parts, body) = response.into_parts();
277
+ let boxed_body = body.map_err(|_: std::convert::Infallible| unreachable!()).boxed();
278
+ Ok(Response::from_parts(parts, boxed_body))
258
279
  }
259
280
  }
260
281
 
@@ -305,39 +326,27 @@ async fn handle_websocket_forwarding(
305
326
  }
306
327
 
307
328
  async fn handle_connection(
308
- req: Request<Body>,
329
+ req: Request<Incoming>,
309
330
  proxy: Arc<FBIProxy>,
310
- ) -> Result<Response<Body>, Infallible> {
331
+ ) -> Result<Response<BoxBody>, Infallible> {
311
332
  match proxy.handle_request(req).await {
312
333
  Ok(response) => Ok(response),
313
334
  Err(e) => {
314
335
  error!("Request handling error: {}", e);
315
336
  Ok(Response::builder()
316
337
  .status(StatusCode::INTERNAL_SERVER_ERROR)
317
- .body(Body::from("Internal Server Error"))
338
+ .body(Full::new(Bytes::from("Internal Server Error")).map_err(|e| match e {}).boxed())
318
339
  .unwrap())
319
340
  }
320
341
  }
321
342
  }
322
343
 
323
- pub async fn start_proxy_server(port: u16) -> Result<(), BoxError> {
324
- start_proxy_server_with_options("127.0.0.1", port, None).await
325
- }
326
-
327
- pub async fn start_proxy_server_with_host(host: &str, port: u16) -> Result<(), BoxError> {
328
- start_proxy_server_with_options(host, port, None).await
329
- }
330
-
331
- pub async fn start_proxy_server_with_options(host: &str, port: u16, domain_filter: Option<String>) -> Result<(), BoxError> {
344
+ pub async fn start_proxy_server(host: Option<&str>, port: u16, domain_filter: Option<String>) -> Result<(), BoxError> {
345
+ let host = host.unwrap_or("127.0.0.1");
332
346
  let addr: SocketAddr = format!("{}:{}", host, port).parse()?;
333
347
  let proxy = Arc::new(FBIProxy::new(domain_filter.clone()));
334
348
 
335
- let make_svc = make_service_fn(move |_conn: &hyper::server::conn::AddrStream| {
336
- let proxy = proxy.clone();
337
- async move { Ok::<_, Infallible>(service_fn(move |req| handle_connection(req, proxy.clone()))) }
338
- });
339
-
340
- let server = Server::bind(&addr).serve(make_svc);
349
+ let listener = TcpListener::bind(addr).await?;
341
350
 
342
351
  info!("FBI Proxy server running on http://{}", addr);
343
352
  println!("FBI Proxy listening on: http://{}", addr);
@@ -351,17 +360,31 @@ pub async fn start_proxy_server_with_options(host: &str, port: u16, domain_filte
351
360
 
352
361
  info!("Features: HTTP proxying + WebSocket forwarding + Port encoding + Domain filtering");
353
362
 
354
- if let Err(e) = server.await {
355
- error!("Server error: {}", e);
356
- }
363
+ loop {
364
+ let (stream, _) = listener.accept().await?;
365
+ let io = TokioIo::new(stream);
366
+ let proxy = proxy.clone();
357
367
 
358
- Ok(())
368
+ tokio::task::spawn(async move {
369
+ let service = service_fn(move |req| handle_connection(req, proxy.clone()));
370
+
371
+ if let Err(err) = http1::Builder::new()
372
+ .preserve_header_case(true)
373
+ .title_case_headers(true)
374
+ .serve_connection(io, service)
375
+ .with_upgrades()
376
+ .await
377
+ {
378
+ error!("Error serving connection: {:?}", err);
379
+ }
380
+ });
381
+ }
359
382
  }
360
383
 
361
384
  fn main() {
362
385
  env_logger::init();
363
386
 
364
- let matches = Command::new("fbi-proxy")
387
+ let matches = Command::new(env!("CARGO_CRATE_NAME"))
365
388
  .version("0.1.1")
366
389
  .about("A fast and flexible proxy server with smart host header parsing and WebSocket support")
367
390
  .long_about(
@@ -454,7 +477,7 @@ TRY RUN:
454
477
  "Starting FBI-Proxy on {}:{} with domain filter: {:?}",
455
478
  host, port, domain_filter
456
479
  );
457
- if let Err(e) = start_proxy_server_with_options(host, port, domain_filter).await {
480
+ if let Err(e) = start_proxy_server(Some(host), port, domain_filter).await {
458
481
  error!("Failed to start proxy server: {}", e);
459
482
  }
460
483
  });
@@ -1,9 +1,7 @@
1
- import fsp from "fs/promises";
2
1
  import { existsSync } from "fs";
2
+ import { chmod } from "fs/promises";
3
3
  import { getFbiProxyFilename } from "./getProxyFilename";
4
- import { copyFile } from "fs/promises";
5
4
  import { $ } from "./dSpawn";
6
- import { mkdir } from "fs/promises";
7
5
 
8
6
  if (import.meta.main) {
9
7
  await getFbiProxyBinary();
@@ -24,15 +22,25 @@ export async function getFbiProxyBinary({ rebuild = false } = {}) {
24
22
 
25
23
  // return built if exists
26
24
  if (!rebuild && existsSync(built)) {
25
+ // Ensure the binary has execute permissions
26
+ await chmod(built, 0o755).catch(() => {}); // Ignore errors if we can't change permissions
27
27
  return built;
28
28
  }
29
29
 
30
30
  // return release if exists
31
- if (!rebuild && existsSync(release)) return release;
31
+ if (!rebuild && existsSync(release)) {
32
+ // Ensure the binary has execute permissions
33
+ await chmod(release, 0o755).catch(() => {}); // Ignore errors if we can't change permissions
34
+ return release;
35
+ }
32
36
 
33
37
  // build and return built target
34
38
  await $`cargo build --release`;
35
- if (existsSync(built)) return built;
39
+ if (existsSync(built)) {
40
+ // Ensure the binary has execute permissions
41
+ await chmod(built, 0o755).catch(() => {}); // Ignore errors if we can't change permissions
42
+ return built;
43
+ }
36
44
 
37
45
  throw new Error(
38
46
  "Oops, failed to build fbi-proxy binary. Please check your Rust setup.",
package/ts/cli.ts CHANGED
@@ -6,22 +6,11 @@ import yargs from "yargs";
6
6
  import { hideBin } from "yargs/helpers";
7
7
  import { getFbiProxyBinary } from "./buildFbiProxy";
8
8
  import { $ } from "./dSpawn";
9
- import { downloadCaddy } from "./downloadCaddy";
10
9
 
11
10
  process.chdir(path.resolve(import.meta.dir, "..")); // Change to project root directory
12
11
 
13
12
  // Parse command line arguments with yargs
14
- const argv = await yargs(hideBin(process.argv))
15
- .option("fbihost", {
16
- type: "string",
17
- default: "fbi.com",
18
- description: "Set the FBI host",
19
- })
20
- .option("caddy", {
21
- type: "boolean",
22
- default: false,
23
- description: "Start Caddy server",
24
- })
13
+ await yargs(hideBin(process.argv))
25
14
  .option("dev", {
26
15
  alias: "d",
27
16
  type: "boolean",
@@ -32,7 +21,6 @@ const argv = await yargs(hideBin(process.argv))
32
21
 
33
22
  console.log("Preparing Binaries");
34
23
 
35
- const FBIHOST = argv.fbihost;
36
24
  const FBIPROXY_PORT = String(await getPort({ port: 2432 }));
37
25
 
38
26
  const proxyProcess = await hotMemo(async () => {
@@ -52,40 +40,13 @@ const proxyProcess = await hotMemo(async () => {
52
40
  return p;
53
41
  });
54
42
 
55
- let caddyProcess: any = null;
56
-
57
- // Only start Caddy if --caddy flag is passed
58
- if (argv.caddy) {
59
- const caddy = await downloadCaddy();
60
- caddyProcess = await hotMemo(async () => {
61
- const p = $.opt({
62
- env: {
63
- ...process.env,
64
- FBIPROXY_PORT, // Rust proxy server port
65
- FBIHOST,
66
- },
67
- })`${caddy} run`.process;
68
- p.on("exit", (code) => {
69
- console.log(`Caddy exited with code ${code}`);
70
- process.exit(code || 0);
71
- });
72
- return p;
73
- });
74
- }
75
-
76
43
  console.log("All services started successfully!");
77
- // show process pids
78
44
  console.log(`Proxy server PID: ${proxyProcess.pid}`);
79
- if (caddyProcess) {
80
- console.log(`Caddy server PID: ${caddyProcess.pid}`);
81
- } else {
82
- console.log("Caddy server not started (use --caddy to start it)");
83
- }
45
+ console.log(`Proxy server running on port: ${FBIPROXY_PORT}`);
84
46
 
85
47
  const exit = () => {
86
48
  console.log("Shutting down...");
87
49
  proxyProcess?.kill?.();
88
- caddyProcess?.kill?.();
89
50
  process.exit(0);
90
51
  };
91
52
  process.on("SIGINT", exit);
package/Caddyfile DELETED
@@ -1,47 +0,0 @@
1
- {
2
- admin off
3
- # TODO: add ondemand tls endpoint to cli.ts
4
- # - [Global options (Caddyfile) — Caddy Documentation]( https://caddyserver.com/docs/caddyfile/options#on-demand-tls )
5
- # make a endpoint to handle /CHECK_TLS?domain=..., and return 200 if domain is valid
6
- #
7
- # on_demand_tls {
8
- # ask http://localhost:{$PROX}/CHECK_TLS
9
- # }
10
- servers {
11
- trusted_proxies static private_ranges
12
- trusted_proxies_strict
13
- }
14
- # auto_https disable_redirects
15
- }
16
-
17
- # unwrap all https
18
- http://*, http://*.*, http://*.*.*, http://*.*.*.*, https://*, https://*.*, https://*.*.*, https://*.*.*.* {
19
- tls internal {
20
- on_demand
21
- }
22
- # match **.fbi.com use regex match against to host
23
- @subhost {
24
- header_regexp subhost Host ^((?:(.+)\.)?{$FBIHOST:fbi.com})$
25
- }
26
- @fullhost {
27
- header_regexp fullhost Host ^(.+)$
28
- }
29
- # debug
30
- # handle @subhost {
31
- # respond "https://{re.subhost.1}{uri} => http://{re.subhost.2}{uri}"
32
- # }
33
-
34
- reverse_proxy @subhost :{$FBIPROXY_PORT:24306} {
35
- # strip the fbi.com part from the host
36
- header_up Host {re.subhost.2}
37
- # header_up X-Forwarded-Host {re.subhost.1}
38
- }
39
- reverse_proxy @fullhost :{$FBIPROXY_PORT:24306} {
40
- header_up Host {re.fullhost.1}
41
- }
42
-
43
- # 3000.amd.fbi.com => *.amd.fbi.com goes to amd.fbi.com with 3000.localhost host
44
-
45
- # for all other hosts, 404
46
- # respond 404
47
- }
@@ -1,24 +0,0 @@
1
- import { existsSync } from "fs";
2
- import { $ } from "./dSpawn";
3
-
4
- if (import.meta.main) {
5
- // if this file is run directly, download caddy
6
- const caddy = await downloadCaddy();
7
- console.log(`Caddy downloaded to: ${caddy}`);
8
- process.exit(0);
9
- }
10
-
11
- export async function downloadCaddy() {
12
- // use pwdCaddy if already downloaded
13
- const pwdCaddy = "./node_modules/.bin/caddy";
14
- if (existsSync(pwdCaddy)) return pwdCaddy;
15
-
16
- // // or use system caddy if installed, run `caddy --version` to check
17
- if (await $`caddy --version`.catch(() => false)) {
18
- return "caddy";
19
- }
20
-
21
- throw new Error(
22
- "Failed to download Caddy. Please install Caddy manually or check your network connection.",
23
- );
24
- }