diff --git a/default.conf b/default.conf index 28842e7..61e553d 100644 --- a/default.conf +++ b/default.conf @@ -1,34 +1,83 @@ +# Loaded by the standard nginx image inside the http context. +# TLS is terminated by the existing external reverse proxy (Pangolin). +map $uri $olapka_canonical_path { + # Re-evaluate after internal error_page redirects. + volatile; + default $uri; + ~^/index(?:\.html)?/?$ /; + ~^/(business-animation|contacts|legal|personal-animation|portfolio|services|social-animation)(?:\.html/?|/)$ /$1; +} + server { listen 80; server_name www.olapka.ru; - - return 301 https://olapka.ru$request_uri; + return 301 https://olapka.ru$olapka_canonical_path$is_args$args; } server { listen 80; server_name olapka.ru; - root /usr/share/nginx/html; - index index.html; + charset utf-8; + charset_types text/plain text/css text/markdown application/javascript application/json application/xml image/svg+xml; - # Отдельная страница ошибки 404 - error_page 404 /404.html; + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_min_length 512; + gzip_comp_level 5; + gzip_types text/plain text/css text/markdown application/javascript application/json application/xml text/xml image/svg+xml; - # Убираем .html из исходных запросов браузера - if ($request_uri ~ ^(/[^?]*)\.html(\?.*)?$) { - return 301 $1$is_args$args; + # /404 is an error too, never a successful content page. + location = /404 { + return 404; } - location / { - try_files $uri $uri.html $uri/ =404; - } + error_page 404 =404 /404.html; - # Доступ только для внутренней обработки ошибки location = /404.html { internal; } - # Machine-readable site summaries (UTF-8 Markdown in .txt files). + + # Only return redirects here; no rewrite loops or HTTPS checks behind proxy. + if ($uri != $olapka_canonical_path) { + return 301 https://olapka.ru$olapka_canonical_path$is_args$args; + } + + # try_files serves an existing file in-place, without a client redirect. + location = / { + try_files /index.html =404; + } + + location = /business-animation { + try_files /business-animation.html =404; + } + + location = /contacts { + try_files /contacts.html =404; + } + + location = /legal { + try_files /legal.html =404; + } + + location = /personal-animation { + try_files /personal-animation.html =404; + } + + location = /portfolio { + try_files /portfolio.html =404; + } + + location = /services { + try_files /services.html =404; + } + + location = /social-animation { + try_files /social-animation.html =404; + } + + # Machine-readable site summaries (UTF-8 Markdown in .txt files). location ~ ^/llms(?:-full)?\.txt$ { types { } default_type text/plain; @@ -55,4 +104,15 @@ server { add_header Link '; rel="describedby"'; try_files $uri =404; } -} \ No newline at end of file + + # Revalidate changed assets after one hour (filenames are not versioned). + location ~ ^/(?:css|js|img|video)/ { + add_header Cache-Control "public, max-age=3600"; + try_files $uri =404; + } + + # Real assets are served normally. Unknown URLs return a real 404. + location / { + try_files $uri =404; + } +} diff --git a/default.local.conf b/default.local.conf new file mode 100644 index 0000000..671fce2 --- /dev/null +++ b/default.local.conf @@ -0,0 +1,112 @@ +# Loaded by the standard nginx image inside the http context. +# Local development only: HTTP on localhost:8080. +map $uri $olapka_canonical_path { + # Re-evaluate after internal error_page redirects. + volatile; + default $uri; + ~^/index(?:\.html)?/?$ /; + ~^/(business-animation|contacts|legal|personal-animation|portfolio|services|social-animation)(?:\.html/?|/)$ /$1; +} + +server { + listen 80 default_server; + server_name localhost 127.0.0.1; + root /usr/share/nginx/html; + charset utf-8; + charset_types text/plain text/css text/markdown application/javascript application/json application/xml image/svg+xml; + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_min_length 512; + gzip_comp_level 5; + gzip_types text/plain text/css text/markdown application/javascript application/json application/xml text/xml image/svg+xml; + + # /404 is an error too, never a successful content page. + location = /404 { + return 404; + } + + error_page 404 =404 /404.html; + + location = /404.html { + internal; + } + + # Only return redirects here; no rewrite loops or HTTPS checks behind proxy. + if ($uri != $olapka_canonical_path) { + return 301 http://localhost:8080$olapka_canonical_path$is_args$args; + } + + # try_files serves an existing file in-place, without a client redirect. + location = / { + try_files /index.html =404; + } + + location = /business-animation { + try_files /business-animation.html =404; + } + + location = /contacts { + try_files /contacts.html =404; + } + + location = /legal { + try_files /legal.html =404; + } + + location = /personal-animation { + try_files /personal-animation.html =404; + } + + location = /portfolio { + try_files /portfolio.html =404; + } + + location = /services { + try_files /services.html =404; + } + + location = /social-animation { + try_files /social-animation.html =404; + } + + # Machine-readable site summaries (UTF-8 Markdown in .txt files). + location ~ ^/llms(?:-full)?\.txt$ { + types { } + default_type text/plain; + charset utf-8; + add_header Cache-Control "public, max-age=3600"; + try_files $uri =404; + } + + # Keep the source legal page's noindex policy on its Markdown copy. + location = /legal.md { + types { } + default_type text/markdown; + charset utf-8; + add_header X-Robots-Tag "noindex, follow"; + add_header Link '; rel="describedby"'; + try_files $uri =404; + } + + location ~ ^/(index|services|personal-animation|business-animation|social-animation|portfolio|contacts)\.md$ { + types { } + default_type text/markdown; + charset utf-8; + add_header Cache-Control "public, max-age=3600"; + add_header Link '; rel="describedby"'; + try_files $uri =404; + } + + # Revalidate changed assets after one hour (filenames are not versioned). + location ~ ^/(?:css|js|img|video)/ { + add_header Cache-Control "public, max-age=3600"; + try_files $uri =404; + } + + # Real assets are served normally. Unknown URLs return a real 404. + location / { + try_files $uri =404; + } +} diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000..dcf625e --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,8 @@ +services: + nginx: + image: nginx:stable-alpine + ports: + - "127.0.0.1:8080:80" + volumes: + - ./html:/usr/share/nginx/html:ro + - ./default.local.conf:/etc/nginx/conf.d/default.conf:ro diff --git a/html/404.html b/html/404.html index def5fef..e519198 100644 --- a/html/404.html +++ b/html/404.html @@ -5,18 +5,18 @@ Страница не найдена — О’ляпка - + - - + +
- - Связаться со студией + + Связаться со студией
diff --git a/html/business-animation.html b/html/business-animation.html index 9e25236..09b02ca 100644 --- a/html/business-animation.html +++ b/html/business-animation.html @@ -4,22 +4,22 @@ - + - + Рекламные анимационные ролики для бизнеса — О’ляпка - + - + @@ -50,7 +50,7 @@ "telephone": "+79160957383", "contactType": "customer service", "availableLanguage": "ru", - "url": "https://olapka.ru/contacts.html" + "url": "https://olapka.ru/contacts" } }, { @@ -65,8 +65,8 @@ }, { "@type": "WebPage", - "@id": "https://olapka.ru/business-animation.html#webpage", - "url": "https://olapka.ru/business-animation.html", + "@id": "https://olapka.ru/business-animation#webpage", + "url": "https://olapka.ru/business-animation", "name": "Рекламные анимационные ролики для бизнеса — О’ляпка", "description": "ИИ-анимация для рекламы, презентации продукта и истории бренда. Объясняем идеи через персонажей и сюжет.", "inLanguage": "ru", @@ -77,15 +77,15 @@ "@id": "https://olapka.ru/#organization" }, "breadcrumb": { - "@id": "https://olapka.ru/business-animation.html#breadcrumbs" + "@id": "https://olapka.ru/business-animation#breadcrumbs" }, "mainEntity": { - "@id": "https://olapka.ru/business-animation.html#service" + "@id": "https://olapka.ru/business-animation#service" } }, { "@type": "BreadcrumbList", - "@id": "https://olapka.ru/business-animation.html#breadcrumbs", + "@id": "https://olapka.ru/business-animation#breadcrumbs", "itemListElement": [ { "@type": "ListItem", @@ -97,23 +97,23 @@ "@type": "ListItem", "position": 2, "name": "Услуги", - "item": "https://olapka.ru/services.html" + "item": "https://olapka.ru/services" }, { "@type": "ListItem", "position": 3, "name": "Рекламные анимационные ролики для бизнеса", - "item": "https://olapka.ru/business-animation.html" + "item": "https://olapka.ru/business-animation" } ] }, { "@type": "Service", - "@id": "https://olapka.ru/business-animation.html#service", + "@id": "https://olapka.ru/business-animation#service", "name": "Рекламные анимационные ролики для бизнеса", "description": "ИИ-анимация для рекламы, презентации продукта и истории бренда. Объясняем идеи через персонажей и сюжет.", "serviceType": "Рекламные анимационные ролики для бизнеса", - "url": "https://olapka.ru/business-animation.html", + "url": "https://olapka.ru/business-animation", "provider": { "@id": "https://olapka.ru/#organization" } @@ -123,7 +123,7 @@
@@ -356,26 +356,26 @@

Вопросы о заказе мультфильма

-
Сколько стоит мультфильм?

Тарифы студии: 2 500 ₽, 4 500 ₽ и 9 000 ₽. Состав и длительность указаны выше. Дополнительные сцены, срочность и адаптации оплачиваются отдельно.

Сколько времени занимает работа?

Срок зависит от сценария, длительности и количества правок. Дату готовности согласуем до начала работы. Срочное изготовление обсуждается отдельно.

Как заказать?

Откройте контакты и напишите в удобный мессенджер: кому нужен ролик, для чего и к какой дате.

+
Сколько стоит мультфильм?

Тарифы студии: 2 500 ₽, 4 500 ₽ и 9 000 ₽. Состав и длительность указаны выше. Дополнительные сцены, срочность и адаптации оплачиваются отдельно.

Сколько времени занимает работа?

Срок зависит от сценария, длительности и количества правок. Дату готовности согласуем до начала работы. Срочное изготовление обсуждается отдельно.

Как заказать?

Откройте контакты и напишите в удобный мессенджер: кому нужен ролик, для чего и к какой дате.

- + diff --git a/html/sitemap.xml b/html/sitemap.xml index 2cc8453..8b558ab 100644 --- a/html/sitemap.xml +++ b/html/sitemap.xml @@ -1,10 +1,10 @@ - https://olapka.ru/contacts.html2026-10-30 - https://olapka.ru/2026-10-30 - https://olapka.ru/services.html2026-10-30 - https://olapka.ru/portfolio.html2026-10-30 - https://olapka.ru/personal-animation.html2026-10-30 - https://olapka.ru/business-animation.html2026-10-30 - https://olapka.ru/social-animation.html2026-10-30 + https://olapka.ru/contacts2026-10-31 + https://olapka.ru/2026-10-31 + https://olapka.ru/services2026-10-31 + https://olapka.ru/portfolio2026-10-31 + https://olapka.ru/personal-animation2026-10-31 + https://olapka.ru/business-animation2026-10-31 + https://olapka.ru/social-animation2026-10-31 diff --git a/html/social-animation.html b/html/social-animation.html index cc79fe1..63218fa 100644 --- a/html/social-animation.html +++ b/html/social-animation.html @@ -4,22 +4,22 @@ - + - + Анимационные ролики для соцсетей — О’ляпка - + - + @@ -50,7 +50,7 @@ "telephone": "+79160957383", "contactType": "customer service", "availableLanguage": "ru", - "url": "https://olapka.ru/contacts.html" + "url": "https://olapka.ru/contacts" } }, { @@ -65,8 +65,8 @@ }, { "@type": "WebPage", - "@id": "https://olapka.ru/social-animation.html#webpage", - "url": "https://olapka.ru/social-animation.html", + "@id": "https://olapka.ru/social-animation#webpage", + "url": "https://olapka.ru/social-animation", "name": "Анимационные ролики для соцсетей — О’ляпка", "description": "Мультики для Reels, Stories, ВКонтакте и Telegram: отдельные ролики, сезонные сюжеты и серии в едином стиле.", "inLanguage": "ru", @@ -77,15 +77,15 @@ "@id": "https://olapka.ru/#organization" }, "breadcrumb": { - "@id": "https://olapka.ru/social-animation.html#breadcrumbs" + "@id": "https://olapka.ru/social-animation#breadcrumbs" }, "mainEntity": { - "@id": "https://olapka.ru/social-animation.html#service" + "@id": "https://olapka.ru/social-animation#service" } }, { "@type": "BreadcrumbList", - "@id": "https://olapka.ru/social-animation.html#breadcrumbs", + "@id": "https://olapka.ru/social-animation#breadcrumbs", "itemListElement": [ { "@type": "ListItem", @@ -97,23 +97,23 @@ "@type": "ListItem", "position": 2, "name": "Услуги", - "item": "https://olapka.ru/services.html" + "item": "https://olapka.ru/services" }, { "@type": "ListItem", "position": 3, "name": "Анимационные ролики для соцсетей", - "item": "https://olapka.ru/social-animation.html" + "item": "https://olapka.ru/social-animation" } ] }, { "@type": "Service", - "@id": "https://olapka.ru/social-animation.html#service", + "@id": "https://olapka.ru/social-animation#service", "name": "Анимационные ролики для соцсетей", "description": "Мультики для Reels, Stories, ВКонтакте и Telegram: отдельные ролики, сезонные сюжеты и серии в едином стиле.", "serviceType": "Анимационные ролики для соцсетей", - "url": "https://olapka.ru/social-animation.html", + "url": "https://olapka.ru/social-animation", "provider": { "@id": "https://olapka.ru/#organization" } @@ -123,7 +123,7 @@