ваше сообщение коммита

This commit is contained in:
2026-01-18 20:55:58 +03:00
parent b8b4269fe8
commit 18ee6aa1ae
5 changed files with 196 additions and 7 deletions

View File

@@ -18,6 +18,13 @@
</head> </head>
<body> <body>
<noscript>
<div style="padding: 20px; text-align: center; font-family: Arial, sans-serif;">
<h1>JavaScript требуется</h1>
<p>Для работы этого приложения необходимо включить JavaScript в вашем браузере.</p>
<p>Please enable JavaScript in your browser to use this application.</p>
</div>
</noscript>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.js"></script>
</body> </body>

View File

@@ -14,20 +14,32 @@ http {
# limit_req_zone $binary_remote_addr zone=api_limit_per_ip:10m rate=5r/s; # limit_req_zone $binary_remote_addr zone=api_limit_per_ip:10m rate=5r/s;
# Блокировка известных сканеров и вредоносных ботов (исключая легитимные поисковые боты) # Блокировка известных сканеров и вредоносных ботов (исключая легитимные поисковые боты)
# ВАЖНО: Сначала проверяем легитимные боты, потом блокируем вредоносные
map $http_user_agent $bad_bot { map $http_user_agent $bad_bot {
default 0; default 0;
# Разрешаем легитимные поисковые боты # Разрешаем легитимные поисковые боты (проверяем ПЕРВЫМИ)
~*googlebot 0; ~*googlebot 0;
~*google.*bot 0;
~*bingbot 0; ~*bingbot 0;
~*bingpreview 0;
~*slurp 0; ~*slurp 0;
~*duckduckbot 0; ~*duckduckbot 0;
~*baiduspider 0; ~*baiduspider 0;
~*yandex 0; ~*yandex 0;
~*yandexbot 0;
~*sogou 0; ~*sogou 0;
~*exabot 0; ~*exabot 0;
~*facebot 0; ~*facebot 0;
~*facebookexternalhit 0;
~*ia_archiver 0; ~*ia_archiver 0;
# Блокируем вредоносные боты и сканеры ~*archive\.org_bot 0;
~*applebot 0;
~*twitterbot 0;
~*linkedinbot 0;
~*slackbot 0;
~*whatsapp 0;
~*telegrambot 0;
# Блокируем вредоносные боты и сканеры (только если не поисковый бот)
~*sqlmap 1; ~*sqlmap 1;
~*nikto 1; ~*nikto 1;
~*dirb 1; ~*dirb 1;
@@ -40,10 +52,12 @@ http {
~*masscan 1; ~*masscan 1;
~*nmap 1; ~*nmap 1;
~*scanner 1; ~*scanner 1;
~*Chrome/[1-4][0-9]\. 1; # Блокируем старые версии браузеров (только если это не поисковый бот)
~*Firefox/[1-6][0-9]\. 1; # Убираем блокировку старых браузеров - может блокировать легитимных ботов
~*Safari/[1-9]\. 1; # ~*Chrome/[1-4][0-9]\. 1;
~*MSIE\ [1-9]\. 1; # ~*Firefox/[1-6][0-9]\. 1;
# ~*Safari/[1-9]\. 1;
# ~*MSIE\ [1-9]\. 1;
} }
# HTTP сервер - редирект на HTTPS # HTTP сервер - редирект на HTTPS

View File

@@ -246,6 +246,120 @@ watch(() => page.value?.content, () => {
} }
}); });
// Установка мета-тегов для SEO
function updatePageMetaTags() {
if (!page.value) return;
// Парсим seo, если это строка
let seoData = page.value.seo;
if (typeof seoData === 'string') {
try {
seoData = JSON.parse(seoData);
} catch (e) {
console.warn('Ошибка парсинга SEO данных:', e);
seoData = null;
}
}
const title = seoData?.title || page.value.title || 'Публичная страница';
const description = seoData?.description || page.value.summary || '';
const keywords = seoData?.keywords || '';
// Определяем canonical URL
const pageUrl = page.value.slug
? `${window.location.origin}/content/published/${encodeURIComponent(page.value.slug)}`
: `${window.location.origin}/content/published?page=${page.value.id}`;
// Обновляем title
document.title = title;
// Обновляем или создаем meta теги
const updateOrCreateMeta = (name, content, attribute = 'name') => {
if (!content) return;
let meta = document.querySelector(`meta[${attribute}="${name}"]`);
if (!meta) {
meta = document.createElement('meta');
meta.setAttribute(attribute, name);
document.head.appendChild(meta);
}
meta.setAttribute('content', content);
};
// Meta description
updateOrCreateMeta('description', description);
// Meta keywords
if (keywords) {
updateOrCreateMeta('keywords', keywords);
}
// Canonical URL
let canonical = document.querySelector('link[rel="canonical"]');
if (!canonical) {
canonical = document.createElement('link');
canonical.setAttribute('rel', 'canonical');
document.head.appendChild(canonical);
}
canonical.setAttribute('href', pageUrl);
// Open Graph теги для социальных сетей
updateOrCreateMeta('og:title', title, 'property');
updateOrCreateMeta('og:description', description, 'property');
updateOrCreateMeta('og:type', 'article', 'property');
updateOrCreateMeta('og:url', pageUrl, 'property');
// Robots meta
updateOrCreateMeta('robots', 'index, follow');
// Добавляем JSON-LD разметку для статьи
addArticleJsonLd(page.value, pageUrl, seoData);
}
// Добавляем JSON-LD разметку для статьи
function addArticleJsonLd(pageData, canonicalUrl, seoData) {
// Удаляем старую разметку, если есть
const oldScript = document.querySelector('script[type="application/ld+json"][data-public-article]');
if (oldScript) {
oldScript.remove();
}
const articleJsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
'headline': seoData?.title || pageData.title || '',
'description': seoData?.description || pageData.summary || '',
'datePublished': pageData.created_at || '',
'dateModified': pageData.updated_at || pageData.created_at || '',
'url': canonicalUrl,
'author': {
'@type': 'Organization',
'name': 'HB3 Accelerator'
},
'publisher': {
'@type': 'Organization',
'name': 'HB3 Accelerator',
'url': window.location.origin
}
};
if (pageData.category) {
articleJsonLd.articleSection = pageData.category;
}
const script = document.createElement('script');
script.type = 'application/ld+json';
script.setAttribute('data-public-article', 'true');
script.textContent = JSON.stringify(articleJsonLd);
document.head.appendChild(script);
}
// Отслеживаем загрузку страницы и обновляем мета-теги
watch(() => page.value, (newPage) => {
if (newPage) {
updatePageMetaTags();
}
}, { immediate: true });
// Загрузка данных // Загрузка данных
onMounted(() => { onMounted(() => {
loadPage(); loadPage();

View File

@@ -158,8 +158,56 @@ async function loadPages() {
} }
} }
// Установка мета-тегов для SEO
function updatePublicPagesMetaTags() {
const title = 'Публичные документы - HB3 Accelerator';
const description = 'Опубликованные документы и материалы платформы Digital Legal Entity. Публичная документация, статьи и информационные материалы.';
const keywords = 'публичные документы, документация, Digital Legal Entity, DLE, публикации';
const canonicalUrl = `${window.location.origin}/content/published`;
// Обновляем title
document.title = title;
// Обновляем или создаем meta теги
const updateOrCreateMeta = (name, content, attribute = 'name') => {
if (!content) return;
let meta = document.querySelector(`meta[${attribute}="${name}"]`);
if (!meta) {
meta = document.createElement('meta');
meta.setAttribute(attribute, name);
document.head.appendChild(meta);
}
meta.setAttribute('content', content);
};
// Meta description
updateOrCreateMeta('description', description);
// Meta keywords
updateOrCreateMeta('keywords', keywords);
// Canonical URL
let canonical = document.querySelector('link[rel="canonical"]');
if (!canonical) {
canonical = document.createElement('link');
canonical.setAttribute('rel', 'canonical');
document.head.appendChild(canonical);
}
canonical.setAttribute('href', canonicalUrl);
// Open Graph теги для социальных сетей
updateOrCreateMeta('og:title', title, 'property');
updateOrCreateMeta('og:description', description, 'property');
updateOrCreateMeta('og:type', 'website', 'property');
updateOrCreateMeta('og:url', canonicalUrl, 'property');
// Robots meta
updateOrCreateMeta('robots', 'index, follow');
}
// Загрузка данных // Загрузка данных
onMounted(() => { onMounted(() => {
updatePublicPagesMetaTags();
loadPages(); loadPages();
}); });
</script> </script>

View File

@@ -10,7 +10,7 @@ NC='\033[0m' # No Color
echo -e "${GREEN}🔄 Синхронизация кода с VDS...${NC}" echo -e "${GREEN}🔄 Синхронизация кода с VDS...${NC}"
# Параметры VDS (из настроек) # Параметры VDS (из настроек)
VDS_HOST="185.221.214.140" VDS_HOST="185.26.121.127"
VDS_USER="root" VDS_USER="root"
VDS_PORT="22" VDS_PORT="22"
VDS_PATH="/home/docker/dapp" VDS_PATH="/home/docker/dapp"
@@ -139,6 +139,12 @@ scp $SCP_OPTS ./backend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/backend/Docker
scp $SCP_OPTS ./frontend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/Dockerfile" 2>/dev/null || true scp $SCP_OPTS ./frontend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/Dockerfile" 2>/dev/null || true
scp $SCP_OPTS ./frontend/nginx.Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/nginx.Dockerfile" 2>/dev/null || true scp $SCP_OPTS ./frontend/nginx.Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/nginx.Dockerfile" 2>/dev/null || true
# Синхронизация nginx конфигураций (критично для SEO исправлений)
echo -e "${YELLOW}📦 Синхронизация nginx конфигураций...${NC}"
scp $SCP_OPTS ./frontend/nginx-simple.conf "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/nginx-simple.conf" 2>/dev/null || true
scp $SCP_OPTS ./frontend/nginx-local.conf "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/nginx-local.conf" 2>/dev/null || true
scp $SCP_OPTS ./frontend/docker-entrypoint.sh "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/docker-entrypoint.sh" 2>/dev/null || true
echo -e "${GREEN}✅ Синхронизация завершена!${NC}" echo -e "${GREEN}✅ Синхронизация завершена!${NC}"
# Спрашиваем, нужно ли пересобрать образы # Спрашиваем, нужно ли пересобрать образы