Skip to content

Commit 76ea2d7

Browse files
EstrellaXDclaude
andcommitted
feat: serve frontend from Axum, single unified Docker image
Replace separate backend/frontend containers with a single image. Axum now serves the Vue frontend via ServeDir fallback, eliminating the Nginx container. Multi-stage Dockerfile builds both frontend and backend in one image. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 18bdb39 commit 76ea2d7

5 files changed

Lines changed: 84 additions & 5 deletions

File tree

.github/workflows/docker-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
- name: Build and push Docker image
4242
uses: docker/build-push-action@v6
4343
with:
44-
context: ./backend
44+
context: .
4545
platforms: linux/amd64,linux/arm64
4646
push: true
4747
tags: ${{ steps.meta.outputs.tags }}

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM node:20-alpine AS frontend
2+
3+
WORKDIR /build
4+
COPY frontend/package*.json ./
5+
RUN npm ci
6+
COPY frontend/ .
7+
RUN npm run build
8+
9+
FROM rust:1.83-slim AS backend
10+
11+
WORKDIR /build
12+
13+
RUN apt-get update && apt-get install -y --no-install-recommends \
14+
pkg-config \
15+
libssl-dev \
16+
&& rm -rf /var/lib/apt/lists/*
17+
18+
COPY backend/Cargo.toml backend/Cargo.lock ./
19+
RUN mkdir src && echo "fn main() {}" > src/main.rs && echo "" > src/lib.rs
20+
RUN cargo build --release 2>/dev/null || true
21+
RUN rm -rf src
22+
23+
COPY backend/src/ src/
24+
RUN touch src/main.rs src/lib.rs
25+
RUN cargo build --release
26+
27+
FROM debian:bookworm-slim
28+
29+
RUN apt-get update && apt-get install -y --no-install-recommends \
30+
ca-certificates \
31+
libssl3 \
32+
curl \
33+
&& rm -rf /var/lib/apt/lists/*
34+
35+
WORKDIR /app
36+
37+
COPY --from=backend /build/target/release/server-monitor /app/server-monitor
38+
COPY --from=frontend /build/dist /app/static
39+
40+
EXPOSE 8742
41+
42+
CMD ["/app/server-monitor"]

backend/Cargo.lock

Lines changed: 33 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "server-monitor"
3-
version = "1.0.0"
3+
version = "1.2.0"
44
edition = "2021"
55
rust-version = "1.75"
66

@@ -18,7 +18,7 @@ reqwest = { version = "0.12", features = ["json", "cookies", "rustls-tls"], defa
1818
russh = "0.48"
1919
russh-keys = "0.48"
2020
bollard = "0.18"
21-
tower-http = { version = "0.6", features = ["cors"] }
21+
tower-http = { version = "0.6", features = ["cors", "fs"] }
2222
chrono = { version = "0.4", features = ["serde"] }
2323
thiserror = "2"
2424
anyhow = "1"

backend/src/main.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use axum::routing::{get, post};
55
use axum::Router;
66
use tokio::sync::broadcast;
77
use tower_http::cors::{Any, CorsLayer};
8+
use tower_http::services::{ServeDir, ServeFile};
89

910
use std::collections::HashMap;
1011

@@ -75,8 +76,11 @@ async fn main() {
7576
.allow_methods(Any)
7677
.allow_headers(Any);
7778

79+
let static_dir = std::env::var("SERVERMONITOR_STATIC_DIR")
80+
.unwrap_or_else(|_| "/app/static".to_string());
81+
let index_file = format!("{}/index.html", static_dir);
82+
7883
let app = Router::new()
79-
.route("/", get(routes::root))
8084
.route("/api/systems", get(routes::get_all_systems))
8185
.route("/api/systems/{system_id}", get(routes::get_system))
8286
.route("/api/health", get(routes::health_check))
@@ -90,6 +94,7 @@ async fn main() {
9094
post(routes::qbit_action),
9195
)
9296
.route("/ws", get(websocket::ws_handler))
97+
.fallback_service(ServeDir::new(&static_dir).fallback(ServeFile::new(&index_file)))
9398
.layer(cors)
9499
.with_state(state.clone());
95100

0 commit comments

Comments
 (0)