Add production deployment

This commit is contained in:
2025-08-23 17:17:03 +03:00
Unverified
parent 5b7ba90628
commit 320c6bbe95
11 changed files with 214 additions and 3 deletions
+40
View File
@@ -0,0 +1,40 @@
# Simple workflow for deploying to the self-hosted server
name: Deploy to server
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
workflow_dispatch:
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
runs-on: self-hosted
env:
HOME: "/root"
environment:
name: production
url: https://fromchat.toolbox-io.ru
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build container
run: |
cd deployment
docker compose build
- name: Set up the service
run: |
cp -f deployment/fromchat.service /etc/systemd/system/fromchat.service
systemctl daemon-reload
- name: Start the server
run: |
if ! systemctl restart fromchat && sleep 10 && systemctl status fromchat; then
journalctl --no-pager -xeu fromchat
exit 1
fi
+31
View File
@@ -0,0 +1,31 @@
# Node.js
node_modules
npm-debug.log
.env
.idea
.vscode
# Python
__pycache__/
*.pyc
.pytest_cache/
.mypy_cache/
.ipynb_checkpoints
.venv
venv/
# Git
.git
.gitignore
# macOS
.DS_Store
# Common
# Exclude editor and OS files, as well as test results
/dist
/build
/coverage
/test_results/
data
+19
View File
@@ -0,0 +1,19 @@
FROM python:3.12 AS builder
WORKDIR /app
RUN python3 -m venv .venv
COPY backend/requirements.txt .
RUN ./.venv/bin/pip3 install -r requirements.txt
FROM python:3.12-slim AS runtime
WORKDIR /app
RUN useradd -u 1000 app && \
chown -R app /app
USER app
COPY --chown=app backend .
COPY --from=builder --chown=app /app/.venv .venv
RUN mkdir -p /app/data
ENTRYPOINT exec ./.venv/bin/fastapi run --port ${PORT:-8300} main.py
+25
View File
@@ -0,0 +1,25 @@
services:
backend:
build:
dockerfile: deployment/Dockerfile.backend
context: ..
environment:
PORT: 8300
ports:
- "8300:8300"
volumes:
- "data:/app/data"
frontend:
build:
dockerfile: deployment/frontend/Dockerfile
context: ..
environment:
PORT: 8301
BACKEND_HOST: http://backend:8300
ports:
- "8301:8301"
volumes:
data:
name: fromchat-data
+32
View File
@@ -0,0 +1,32 @@
[Unit]
Description=FromChat server
After=multi-user.target
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=60
StartLimitBurst=3
[Service]
Type=simple
User=root
Group=root
ExecStart=/bin/docker compose up
ExecStop=/bin/docker compose down
WorkingDirectory=/home/denis0001-dev/actions-runner/_work/FromChat/FromChat/deployment
Restart=always
RestartSec=10
# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/log
# Logging
StandardOutput=journal
StandardError=journal
StandardInput=tty-force
SyslogIdentifier=fromchat
[Install]
WantedBy=multi-user.target
+26
View File
@@ -0,0 +1,26 @@
FROM node:24 AS frontend
WORKDIR /app
COPY package.json .
RUN npm install --ignore-scripts
COPY frontend frontend
RUN npm run build
FROM node:24 AS server
WORKDIR /server
COPY deployment/frontend/package.json .
RUN npm install
COPY deployment/frontend/ .
FROM node:24-slim
WORKDIR /app
COPY --from=frontend /app/frontend/dist .
WORKDIR /server
COPY --from=server /server .
ENV STATIC_FILE_PATH=/app
ENTRYPOINT ["npm", "run", "start"]
+12
View File
@@ -0,0 +1,12 @@
{
"name": "frontend-server",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^5.1.0",
"http-proxy-middleware": "^3.0.5"
}
}
+22
View File
@@ -0,0 +1,22 @@
// server.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const path = require('path');
const app = express();
const port = process.env.PORT || 3000;
const backendHost = process.env.BACKEND_HOST || "http://localhost:8300";
const file_path = process.env.STATIC_FILE_PATH || ".";
app.use('/api', createProxyMiddleware({
target: backendHost,
changeOrigin: true,
pathRewrite: { '^/api': '' },
ws: true
}));
app.use(express.static(path.resolve(file_path)));
app.listen(port, () => {
console.log(`Server launched на http://localhost:${port}`);
});
+1 -1
View File
@@ -17,7 +17,7 @@ export const API_BASE_URL: string = '/api';
* @type {string}
* @constant
*/
export const API_FULL_BASE_URL: string = `${location.hostname}:8301/api`;
export const API_FULL_BASE_URL: string = `${location.host}/api`;
/**
* Application name displayed in UI and document title
-1
View File
@@ -27,7 +27,6 @@ body {
}
mdui-dialog {
> *:first-child {
margin-block-start: 0;
}
+6 -1
View File
@@ -17,7 +17,12 @@ import { delay } from "./utils/utils";
* @private
*/
function create(): WebSocket {
return new WebSocket(`ws://${API_FULL_BASE_URL}/chat/ws`);
let prefix = "ws://";
if (location.protocol.includes("https")) {
prefix = "wss://";
}
return new WebSocket(`${prefix}${API_FULL_BASE_URL}/chat/ws`);
}
/**