mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Add production deployment
This commit is contained in:
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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"]
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}`);
|
||||||
|
});
|
||||||
@@ -17,7 +17,7 @@ export const API_BASE_URL: string = '/api';
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @constant
|
* @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
|
* Application name displayed in UI and document title
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mdui-dialog {
|
mdui-dialog {
|
||||||
|
|
||||||
> *:first-child {
|
> *:first-child {
|
||||||
margin-block-start: 0;
|
margin-block-start: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,12 @@ import { delay } from "./utils/utils";
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function create(): WebSocket {
|
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`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user