batman
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
**/dist
|
2926
Cargo.lock
generated
Normal file
2926
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["frontend", "backend"]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
allpaca-models = { path = "common" }
|
||||||
|
reqwest = { version = "0.12.5", features = ["blocking"] }
|
||||||
|
tokio = "1.38.0"
|
||||||
|
prost = "0.13.1"
|
||||||
|
json = "0.12.4"
|
14
backend/Cargo.toml
Normal file
14
backend/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "oracle"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { version = "0.5.1", features = ["serde_json"] }
|
||||||
|
ollama-rs = { version = "0.2.0", features = ["stream"] }
|
||||||
|
allpaca-models = { workspace = true }
|
||||||
|
reqwest = { workspace = true }
|
||||||
|
tokio = { workspace = true }
|
||||||
|
prost = { workspace = true }
|
||||||
|
json = { workspace = true }
|
||||||
|
lazy_static = "1.5.0"
|
4
backend/Dockerfile
Normal file
4
backend/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM rust:slim
|
||||||
|
RUN apt update && apt install -y pkg-config librust-openssl-dev && apt clean
|
||||||
|
RUN cargo install cargo-watch
|
||||||
|
CMD [ "cargo", "watch", "-x", "run" ]
|
11
backend/Rocket.toml
Normal file
11
backend/Rocket.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[default]
|
||||||
|
address = "0.0.0.0"
|
||||||
|
port = 80
|
||||||
|
|
||||||
|
ip_header = "X-Real-IP"
|
||||||
|
log_level = "normal"
|
||||||
|
temp_dir = "/tmp"
|
||||||
|
workers = 4
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
log_level = "debug"
|
56
backend/src/main.rs
Normal file
56
backend/src/main.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#[macro_use] extern crate rocket;
|
||||||
|
mod models;
|
||||||
|
use models::list;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use ollama_rs::Ollama;
|
||||||
|
use rocket::{
|
||||||
|
http::{Header, Status},
|
||||||
|
response::Responder,
|
||||||
|
Request};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref OLLAMA: Arc<Mutex<Ollama>> = Arc::new(Mutex::new(Ollama::new("http://ollama", 11434)));
|
||||||
|
}
|
||||||
|
pub static BASE: &'static str = "http://ollama:11434/api";
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! response {
|
||||||
|
($name:ident, $body:ty) => {
|
||||||
|
pub struct $name {
|
||||||
|
pub status: rocket::http::Status,
|
||||||
|
pub body: $body,
|
||||||
|
}
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> Responder<'r, 'static> for $name {
|
||||||
|
fn respond_to(self, _request: &'r Request) -> rocket::response::Result<'static> {
|
||||||
|
let body: Vec<u8> = self.body.into();
|
||||||
|
rocket::response::Response::build()
|
||||||
|
.header(Header::new("Content-Type", "application/x-protobuf"))
|
||||||
|
.sized_body(body.len(), std::io::Cursor::new(body))
|
||||||
|
.status(self.status)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
response!(Response, &'static str);
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn index() -> Response {
|
||||||
|
Response {
|
||||||
|
status: Status::ImATeapot,
|
||||||
|
body: "Hello, world!",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::main]
|
||||||
|
async fn main() -> Result<(), rocket::Error> {
|
||||||
|
rocket::build()
|
||||||
|
.mount("/", routes![index, models::list])
|
||||||
|
.launch().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
22
backend/src/models.rs
Normal file
22
backend/src/models.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use rocket::{http::{Header, Status}, response::Responder, Request, Response};
|
||||||
|
use json::JsonValue;
|
||||||
|
|
||||||
|
use allpaca_models::{Models, Model};
|
||||||
|
use super::{OLLAMA, BASE, response};
|
||||||
|
|
||||||
|
response!(ListResponse, Models);
|
||||||
|
|
||||||
|
#[get("/models/list")]
|
||||||
|
pub async fn list() -> ListResponse {
|
||||||
|
let models = OLLAMA.lock().await.list_local_models().await.unwrap();
|
||||||
|
ListResponse {
|
||||||
|
status: Status::Ok,
|
||||||
|
body: Models(models.iter().map(|model| {
|
||||||
|
Model {
|
||||||
|
modified_at: model.modified_at.clone(),
|
||||||
|
size: model.size.to_string(),
|
||||||
|
name: model.name.clone(),
|
||||||
|
}
|
||||||
|
}).collect()),
|
||||||
|
}
|
||||||
|
}
|
8
common/Cargo.toml
Normal file
8
common/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "allpaca-models"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
prost = { workspace = true }
|
||||||
|
json = { workspace = true }
|
25
common/src/lib.rs
Normal file
25
common/src/lib.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use json::JsonValue;
|
||||||
|
use prost::{
|
||||||
|
alloc::{
|
||||||
|
string::String,
|
||||||
|
vec::Vec,
|
||||||
|
}, *};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Message)]
|
||||||
|
pub struct Models(#[prost(message, repeated)] pub Vec<Model>);
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Message)]
|
||||||
|
pub struct Model {
|
||||||
|
#[prost(string)]
|
||||||
|
pub modified_at: String,
|
||||||
|
#[prost(string)]
|
||||||
|
pub size: String,
|
||||||
|
#[prost(string)]
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Vec<u8>> for Models {
|
||||||
|
fn into(self) -> Vec<u8> {
|
||||||
|
self.encode_to_vec()
|
||||||
|
}
|
||||||
|
}
|
27
compose.yml
Normal file
27
compose.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
services:
|
||||||
|
ollama:
|
||||||
|
image: ollama/ollama:latest
|
||||||
|
volumes:
|
||||||
|
- /root/.ollama:/root/.ollama
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build: backend
|
||||||
|
working_dir: /opt/allpaca/backend
|
||||||
|
volumes:
|
||||||
|
- ./:/opt/allpaca
|
||||||
|
environment:
|
||||||
|
- RUST_BACKTRACE=1
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build: frontend
|
||||||
|
working_dir: /opt/allpaca/frontend
|
||||||
|
volumes:
|
||||||
|
- ./:/opt/allpaca
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:latest
|
||||||
|
volumes:
|
||||||
|
- ./frontend/dist:/srv/www
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
ports:
|
||||||
|
- 80:80
|
12
frontend/Cargo.toml
Normal file
12
frontend/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "allpaca"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
allpaca-models = { workspace = true }
|
||||||
|
reqwest = { workspace = true }
|
||||||
|
prost = { workspace = true }
|
||||||
|
yew = { version = "0.21.0", features = ["csr"] }
|
||||||
|
wasm-bindgen = "0.2.92"
|
||||||
|
gloo-net = "0.5.0"
|
5
frontend/Dockerfile
Normal file
5
frontend/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
FROM rust:slim
|
||||||
|
RUN rustup default nightly
|
||||||
|
RUN rustup target add wasm32-unknown-unknown
|
||||||
|
RUN cargo install trunk
|
||||||
|
CMD [ "trunk", "watch" ]
|
11
frontend/build.rs
Normal file
11
frontend/build.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
pub static BASE: &'static str = "https://gpt.42069.no/api";
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub static BASE: &'static str = "http://localhost/api";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
println!("cargo::rustc-env=BASE={}", BASE);
|
||||||
|
}
|
||||||
|
}
|
10
frontend/index.html
Normal file
10
frontend/index.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Allpaca</title>
|
||||||
|
<link data-trunk rel="rust" />
|
||||||
|
<link data-trunk rel="css" href="./styles.css" />
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
4
frontend/src/api/mod.rs
Normal file
4
frontend/src/api/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
pub mod models;
|
||||||
|
|
||||||
|
pub static BASE: &'static str = env!("BASE");
|
18
frontend/src/api/models.rs
Normal file
18
frontend/src/api/models.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use prost::Message;
|
||||||
|
use crate::Models;
|
||||||
|
|
||||||
|
macro_rules! path {
|
||||||
|
($path:expr) => {
|
||||||
|
super::BASE.to_owned() + "/models" + $path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list() -> Result<Models, String> {
|
||||||
|
match Models::decode(
|
||||||
|
reqwest::get(path!("/list"))
|
||||||
|
.await.unwrap().text().await.unwrap().as_bytes()
|
||||||
|
) {
|
||||||
|
Err(_err) => Err("API response was not valid protobuf format".to_owned()),
|
||||||
|
Ok(models) => Ok(models),
|
||||||
|
}
|
||||||
|
}
|
59
frontend/src/components/chat.rs
Normal file
59
frontend/src/components/chat.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
pub struct Message {
|
||||||
|
pub content: String,
|
||||||
|
pub is_user: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ChatMsg {
|
||||||
|
Send
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Chat {
|
||||||
|
pub history: Vec<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Chat {
|
||||||
|
type Properties = ();
|
||||||
|
type Message = ChatMsg;
|
||||||
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
|
Self { history: vec![
|
||||||
|
Message {
|
||||||
|
content: "How may I help you today?".to_owned(),
|
||||||
|
is_user: false,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
match msg {
|
||||||
|
ChatMsg::Send => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<div class="chat">
|
||||||
|
{
|
||||||
|
self.history.iter().map(|message| {
|
||||||
|
html! {
|
||||||
|
<div class={ if message.is_user { "user" } else { "assistant" } }>
|
||||||
|
<p>{ &message.content }</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}).collect::<Html>()
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<form class="chat">
|
||||||
|
<div>
|
||||||
|
<input type="textfield" required=true />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onclick={
|
||||||
|
ctx.link().callback(|_| ChatMsg::Send)
|
||||||
|
}>{ "Send" }</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
frontend/src/components/mod.rs
Normal file
53
frontend/src/components/mod.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
pub mod models;
|
||||||
|
pub mod chat;
|
||||||
|
pub mod nav;
|
||||||
|
pub use chat::Chat;
|
||||||
|
|
||||||
|
|
||||||
|
pub enum FetchMsg {
|
||||||
|
Response(String), Fetch,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Fetcher {
|
||||||
|
res: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for FetchMsg {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self::Response(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Fetcher {
|
||||||
|
type Properties = ();
|
||||||
|
type Message = FetchMsg;
|
||||||
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
|
Self { res: String::new() }
|
||||||
|
}
|
||||||
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
match msg {
|
||||||
|
FetchMsg::Response(res) => {
|
||||||
|
self.res = res;
|
||||||
|
true
|
||||||
|
},
|
||||||
|
FetchMsg::Fetch => {
|
||||||
|
ctx.link().send_future((async move || {
|
||||||
|
FetchMsg::from(reqwest::get("http://localhost/api").await.unwrap().text().await.unwrap())
|
||||||
|
})());
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<button onclick={
|
||||||
|
ctx.link().callback(|_| FetchMsg::Fetch)
|
||||||
|
}>{ "balls" }</button>
|
||||||
|
<p>{ &self.res }</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
frontend/src/components/models/list.rs
Normal file
57
frontend/src/components/models/list.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use yew::{Component, Html, html};
|
||||||
|
|
||||||
|
use crate::{STORE, ModelsResult, api};
|
||||||
|
pub struct List(pub Option<ModelsResult>);
|
||||||
|
pub enum ListMsg {
|
||||||
|
List(ModelsResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for List {
|
||||||
|
type Properties = ();
|
||||||
|
type Message = ListMsg;
|
||||||
|
fn create(ctx: &yew::Context<Self>) -> Self {
|
||||||
|
let models = STORE.models.lock().unwrap();
|
||||||
|
if models.is_none() {
|
||||||
|
ctx.link().send_future((async move || {
|
||||||
|
ListMsg::List(api::models::list().await)
|
||||||
|
})());
|
||||||
|
Self(None)
|
||||||
|
} else {
|
||||||
|
Self(models.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn update(&mut self, _ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
match msg {
|
||||||
|
ListMsg::List(models) => self.0 = Some(models),
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
fn view(&self, _ctx: &yew::Context<Self>) -> Html {
|
||||||
|
match &self.0 {
|
||||||
|
None => html! { <div>{ "Loading..." }</div> },
|
||||||
|
Some(result) => {
|
||||||
|
match result {
|
||||||
|
Err(err) => html! { <div class="error">{ err }</div> },
|
||||||
|
Ok(models) => html! {
|
||||||
|
<ul class="model-list">
|
||||||
|
{
|
||||||
|
models.0.iter().map(|model| {
|
||||||
|
let size = model.size.parse::<usize>().unwrap();
|
||||||
|
html! {
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>{ "Name: "} { &model.name }</li>
|
||||||
|
<li>{ "Size: "} { size / ( 1024 * 1024) } { "MiB" }</li>
|
||||||
|
<li>{ "Modified at: "} { &model.modified_at }</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}).collect::<Html>()
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
frontend/src/components/models/mod.rs
Normal file
2
frontend/src/components/models/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod list;
|
||||||
|
pub use list::List;
|
23
frontend/src/components/nav.rs
Normal file
23
frontend/src/components/nav.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
use allpaca_models::Model;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
pub struct Props {
|
||||||
|
// models: Vec<Model>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component]
|
||||||
|
pub fn Bar(props: &Props) -> Html {
|
||||||
|
html! {
|
||||||
|
<ul>
|
||||||
|
<li class="model-dropdown">
|
||||||
|
<select>
|
||||||
|
// { props.models.iter().map(|model| {
|
||||||
|
// html! { <option>{model.name.clone()}</option> }
|
||||||
|
// }).collect::<Html>() }
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
}
|
35
frontend/src/lib.rs
Normal file
35
frontend/src/lib.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(async_closure)]
|
||||||
|
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use yew::Callback;
|
||||||
|
|
||||||
|
pub mod components;
|
||||||
|
pub mod api;
|
||||||
|
|
||||||
|
use allpaca_models::Models;
|
||||||
|
|
||||||
|
pub type ModelsResult = Result<Models, String>;
|
||||||
|
|
||||||
|
pub struct Store {
|
||||||
|
pub models: Mutex<Option<ModelsResult>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static STORE: Store = Store {
|
||||||
|
models: Mutex::new(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Store {
|
||||||
|
fn set_models(&mut self, models: ModelsResult) {
|
||||||
|
*self.models.lock().unwrap() = Some(models);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
|
pub fn log(s: &str);
|
||||||
|
}
|
26
frontend/src/main.rs
Normal file
26
frontend/src/main.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
use allpaca::components::*;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use allpaca::log;
|
||||||
|
|
||||||
|
#[function_component]
|
||||||
|
fn App() -> Html {
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
<div class="navbar">
|
||||||
|
<nav::Bar></nav::Bar>
|
||||||
|
</div>
|
||||||
|
<models::List></models::List>
|
||||||
|
<Chat></Chat>
|
||||||
|
<div>
|
||||||
|
<Fetcher></Fetcher>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
yew::Renderer::<App>::new().render();
|
||||||
|
}
|
12
frontend/styles.css
Normal file
12
frontend/styles.css
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
color: lime;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar, .model-list {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-list > li {
|
||||||
|
margin: 1vh;
|
||||||
|
}
|
41
nginx.conf
Normal file
41
nginx.conf
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
error_log /var/log/nginx/error.log notice;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
worker_processes 2;
|
||||||
|
user nginx;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
#tcp_nopush on;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
#gzip on;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
location / {
|
||||||
|
index index.html;
|
||||||
|
root /srv/www;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
rewrite /api/?(.*) /$1 break;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_pass http://backend:80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user