commit e5195dd9c50643163a7ca40bffed3b3f731aec84 Author: root Date: Thu Feb 12 16:00:15 2026 +0000 initial server version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03fd11a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +__pycache__/ +*.pyc +.env +data/ +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..94f05bc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +RUN mkdir -p /app/data /app/static/img + +EXPOSE 4545 + +CMD ["gunicorn", "-c", "gunicorn_conf.py", "app:app"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..2fa2aff --- /dev/null +++ b/app.py @@ -0,0 +1,255 @@ +from __future__ import annotations + +import os +import sqlite3 +from datetime import datetime +from functools import wraps +from pathlib import Path +from urllib import parse, request as urllib_request + +from flask import Flask, redirect, render_template, request, session, url_for +from werkzeug.security import check_password_hash + + +BASE_DIR = Path(__file__).resolve().parent +DATA_DIR = BASE_DIR / "data" +DB_PATH = DATA_DIR / "infra.db" + +DEFAULT_SETTINGS = { + "company_name": "InfraIT", + "phone_display": "+7 987 297-06-66", + "phone_link": "+79872970666", + "email": "maks@infrait.ru", + "site_url": "https://infrait.ru/", + "yandex_verification": "PASTE_YOUR_YANDEX_VERIFICATION_TOKEN", + "yandex_metrika_id": "", + "telegram_bot_token": "", + "telegram_chat_id": "", + "geo_primary": "Казань и Татарстан — выезд в день запроса", + "geo_secondary": "Россия — удалённая поддержка", +} + +app = Flask(__name__) +app.secret_key = os.getenv("SECRET_KEY", "change-this-secret-key") +app.config.update( + SESSION_COOKIE_HTTPONLY=True, + SESSION_COOKIE_SAMESITE="Lax", +) + +# Fixed admin password hash (plain password is never stored in code). +ADMIN_PASSWORD_HASH = ( + "scrypt:32768:8:1$Ac0t7TD7bUhYLg04$25779398c765417771b888aa15d23dd72ee40bea4e48d0cd" + "7da9e8e386628a099b1f1e75019059be76c73264deb888959c236f6b776d12f4847e6762d5c76f0f" +) + + +def get_db() -> sqlite3.Connection: + DATA_DIR.mkdir(parents=True, exist_ok=True) + conn = sqlite3.connect(DB_PATH, timeout=30) + conn.execute("PRAGMA journal_mode=WAL;") + conn.execute("PRAGMA busy_timeout=30000;") + conn.execute("PRAGMA synchronous=NORMAL;") + conn.row_factory = sqlite3.Row + return conn + + +def init_db() -> None: + with get_db() as conn: + conn.execute( + """ + CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + ) + """ + ) + conn.execute( + """ + CREATE TABLE IF NOT EXISTS leads ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created_at TEXT NOT NULL, + name TEXT NOT NULL, + company TEXT NOT NULL, + phone TEXT NOT NULL, + email TEXT, + city TEXT, + computers TEXT NOT NULL, + message TEXT + ) + """ + ) + for key, value in DEFAULT_SETTINGS.items(): + conn.execute( + "INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", + (key, value), + ) + conn.commit() + + +def get_settings() -> dict[str, str]: + settings = DEFAULT_SETTINGS.copy() + with get_db() as conn: + rows = conn.execute("SELECT key, value FROM settings").fetchall() + for row in rows: + settings[row["key"]] = row["value"] + return settings + + +def update_settings(new_values: dict[str, str]) -> None: + with get_db() as conn: + for key, value in new_values.items(): + conn.execute( + """ + INSERT INTO settings (key, value) + VALUES (?, ?) + ON CONFLICT(key) DO UPDATE SET value=excluded.value + """, + (key, value), + ) + conn.commit() + + +def send_telegram_lead(form_data: dict[str, str], settings: dict[str, str]) -> None: + token = settings.get("telegram_bot_token", "").strip() + chat_id = settings.get("telegram_chat_id", "").strip() + if not token or not chat_id: + return + + message = ( + "Новая заявка InfraIT\n" + f"Имя: {form_data['name']}\n" + f"Компания: {form_data['company']}\n" + f"Телефон: {form_data['phone']}\n" + f"Email: {form_data['email'] or '-'}\n" + f"Город: {form_data['city'] or '-'}\n" + f"ПК: {form_data['computers']}\n" + f"Комментарий: {form_data['message'] or '-'}" + ) + payload = parse.urlencode({"chat_id": chat_id, "text": message}).encode("utf-8") + req = urllib_request.Request( + f"https://api.telegram.org/bot{token}/sendMessage", + data=payload, + method="POST", + ) + try: + urllib_request.urlopen(req, timeout=8).read() + except Exception: + # Ошибка телеграм-уведомления не должна ломать отправку формы. + return + + +def save_lead(form_data: dict[str, str], settings: dict[str, str]) -> None: + with get_db() as conn: + conn.execute( + """ + INSERT INTO leads ( + created_at, name, company, phone, email, city, computers, message + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + datetime.now().isoformat(timespec="seconds"), + form_data["name"], + form_data["company"], + form_data["phone"], + form_data["email"], + form_data["city"], + form_data["computers"], + form_data["message"], + ), + ) + conn.commit() + send_telegram_lead(form_data, settings) + + +def admin_required(view): + @wraps(view) + def wrapped(*args, **kwargs): + if not session.get("admin_logged_in"): + return redirect(url_for("admin_login")) + return view(*args, **kwargs) + + return wrapped + + +def verify_admin_password(password: str) -> bool: + return check_password_hash(ADMIN_PASSWORD_HASH, password) + +init_db() + + +@app.route("/", methods=["GET", "POST"]) +def index(): + success = request.args.get("success") == "1" + error = None + settings = get_settings() + + if request.method == "POST": + form_data = { + "name": request.form.get("name", "").strip(), + "company": request.form.get("company", "").strip(), + "phone": request.form.get("phone", "").strip(), + "email": request.form.get("email", "").strip(), + "city": request.form.get("city", "").strip(), + "computers": request.form.get("computers", "").strip(), + "message": request.form.get("message", "").strip(), + } + + required_fields = ["name", "phone", "company", "computers"] + if any(not form_data[field] for field in required_fields): + error = "Заполните обязательные поля: имя, компания, телефон и количество компьютеров." + else: + save_lead(form_data, settings) + return redirect(url_for("index", success=1) + "#contact") + + return render_template("index.html", success=success, error=error, settings=settings) + + +@app.route("/admin/login", methods=["GET", "POST"]) +def admin_login(): + error = None + + if request.method == "POST": + password = request.form.get("password", "") + if verify_admin_password(password): + session["admin_logged_in"] = True + return redirect(url_for("admin_settings")) + error = "Неверный пароль." + + return render_template("admin_login.html", error=error) + + +@app.route("/admin/logout") +def admin_logout(): + session.pop("admin_logged_in", None) + return redirect(url_for("admin_login")) + + +@app.route("/admin/settings", methods=["GET", "POST"]) +@admin_required +def admin_settings(): + success = request.args.get("saved") == "1" + settings = get_settings() + + if request.method == "POST": + updates: dict[str, str] = {} + for field in DEFAULT_SETTINGS: + updates[field] = request.form.get(field, "").strip() + update_settings(updates) + return redirect(url_for("admin_settings", saved=1)) + + return render_template("admin_settings.html", settings=settings, success=success) + + +@app.route("/health") +def health(): + try: + with get_db() as conn: + conn.execute("SELECT 1") + return {"status": "ok"}, 200 + except Exception: + return {"status": "error"}, 503 + + +if __name__ == "__main__": + init_db() + app.run(debug=True) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5cf427e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: "3.9" + +services: + web: + build: . + container_name: infrait-web + restart: unless-stopped + ports: + - "4545:4545" + volumes: + - ./data:/app/data + - ./static/img:/app/static/img + environment: + - SECRET_KEY=${SECRET_KEY:-change-this-in-prod} + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:4545/health', timeout=3)"] + interval: 20s + timeout: 5s + retries: 5 + start_period: 20s diff --git a/gunicorn_conf.py b/gunicorn_conf.py new file mode 100644 index 0000000..586a0fc --- /dev/null +++ b/gunicorn_conf.py @@ -0,0 +1,14 @@ +import multiprocessing + +bind = "0.0.0.0:4545" +workers = 4 +threads = 4 +timeout = 60 +graceful_timeout = 30 +keepalive = 5 +worker_tmp_dir = "/dev/shm" +max_requests = 1000 +max_requests_jitter = 100 +accesslog = "-" +errorlog = "-" +loglevel = "info" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9fe2d99 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Flask==3.1.0 +gunicorn==23.0.0 diff --git a/static/css/styles.css b/static/css/styles.css new file mode 100644 index 0000000..2131230 --- /dev/null +++ b/static/css/styles.css @@ -0,0 +1,559 @@ +:root { + --bg: #f2f5f8; + --surface: #ffffff; + --surface-2: #e9eef3; + --text: #112031; + --muted: #5a6b7d; + --brand: #0f8c7a; + --brand-dark: #0b695c; + --accent: #f59f00; + --border: #d6e0ea; + --shadow: 0 12px 30px rgba(17, 32, 49, 0.08); + --radius: 18px; +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + font-family: "Manrope", sans-serif; + color: var(--text); + line-height: 1.5; + background: + radial-gradient(circle at 15% -10%, #d4fff6 0, transparent 34%), + radial-gradient(circle at 90% 0%, #ffefcc 0, transparent 28%), + var(--bg); +} + +.container { + width: min(1140px, 92vw); + margin: 0 auto; +} + +.hero { + padding: 24px 0 40px; +} + +.topbar { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 18px; + margin-bottom: 36px; +} + +.brand { + display: inline-flex; + align-items: center; + text-decoration: none; + margin-right: auto; +} + +.brand img { + display: block; + width: clamp(273px, 29vw, 399px); + height: auto; + object-fit: contain; + transform: translateX(-18px); +} + +.brand-fallback { + display: none; + font-family: "Montserrat", sans-serif; + font-size: 1.35rem; + font-weight: 800; + letter-spacing: 0.4px; + color: var(--text); +} + +.nav { + display: flex; + gap: 16px; + flex-wrap: wrap; + justify-content: flex-end; +} + +.nav a { + font-weight: 600; + opacity: 0.88; +} + +.nav a, +.phone, +.footer a { + text-decoration: none; + color: var(--text); +} + +.phone { + font-weight: 700; +} + +.hero-grid { + display: grid; + grid-template-columns: 1.3fr 1fr; + gap: 24px; + align-items: start; +} + +.badge { + display: inline-block; + background: #d6fff6; + color: var(--brand-dark); + border-radius: 999px; + padding: 7px 14px; + font-weight: 700; + font-size: 0.9rem; +} + +h1, +h2, +h3 { + font-family: "Montserrat", sans-serif; + margin-top: 0; + line-height: 1.2; +} + +h1 { + margin: 16px 0; + font-size: clamp(1.8rem, 3vw, 2.8rem); +} + +h2 { + margin-bottom: 10px; + font-size: clamp(1.5rem, 2.2vw, 2.2rem); +} + +.lead, +.section-subtitle { + color: var(--muted); + font-size: 1.03rem; +} + +.cta-row { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin: 22px 0; +} + +.btn { + border: 0; + border-radius: 12px; + padding: 12px 18px; + font-weight: 700; + text-decoration: none; + display: inline-block; + transition: 0.2s ease; +} + +.btn-primary { + background: var(--brand); + color: #fff; +} + +.btn-primary:hover { + background: var(--brand-dark); +} + +.btn-secondary { + background: var(--surface-2); + color: var(--text); +} + +.btn-secondary:hover { + background: #dce4ed; +} + +.geo-note { + margin-top: 8px; + padding: 13px 15px; + border-left: 4px solid var(--accent); + background: #fff9ec; + border-radius: 0 10px 10px 0; +} + +.hero-card, +.card, +.price-card, +.panel, +.lead-form, +.faq-list details { + background: var(--surface); + border: 1px solid var(--border); + box-shadow: var(--shadow); + border-radius: var(--radius); +} + +.hero-card { + padding: 20px; +} + +.hero-card h3 { + margin-bottom: 10px; +} + +.hero-card ul, +.card ul, +.price-card ul, +.panel ul, +.contacts, +.panel ol { + margin: 0; + padding-left: 20px; +} + +.section { + padding: 46px 0; +} + +.cards { + margin-top: 22px; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; +} + +.cards.two { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.card { + padding: 18px; +} + +.card h3 { + margin-bottom: 8px; +} + +.highlight, +.muted { + background: linear-gradient(180deg, rgba(15, 140, 122, 0.06), rgba(15, 140, 122, 0)); +} + +.pricing-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; +} + +.price-card { + padding: 20px; +} + +.price-card.featured { + border: 2px solid var(--brand); + transform: translateY(-6px); +} + +.chip { + display: inline-block; + background: var(--brand); + color: #fff; + border-radius: 999px; + padding: 4px 10px; + font-size: 0.83rem; + margin-bottom: 8px; +} + +.price { + font-size: 1.35rem; + font-weight: 800; + margin: 8px 0; +} + +.for, +.pricing-note { + color: var(--muted); +} + +.two-col { + display: grid; + gap: 16px; + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.panel { + padding: 20px; +} + +.benefits-grid { + display: grid; + gap: 12px; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.benefits-grid article { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 14px; + padding: 14px; +} + +.seo p { + color: #25384d; +} + +.faq-list { + display: grid; + gap: 10px; +} + +.faq-list details { + padding: 14px; +} + +.faq-list summary { + cursor: pointer; + font-weight: 700; +} + +.contact { + background: linear-gradient(175deg, #e8fff8 0%, #eff5ff 100%); +} + +.contacts { + list-style: none; + padding: 0; +} + +.contacts li { + margin-bottom: 8px; +} + +.lead-form { + padding: 18px; + display: grid; + gap: 10px; +} + +.lead-form label { + display: grid; + gap: 5px; + font-weight: 600; +} + +input, +textarea { + width: 100%; + border: 1px solid #bfd0df; + border-radius: 10px; + padding: 10px; + font: inherit; +} + +input:focus, +textarea:focus { + outline: 2px solid rgba(15, 140, 122, 0.28); + border-color: var(--brand); +} + +.form-success, +.form-error { + margin: 0; + border-radius: 9px; + padding: 10px; + font-weight: 700; +} + +.form-success { + background: #dcffee; + color: #0f684f; +} + +.form-error { + background: #ffe2e2; + color: #ab2a2a; +} + +.footer { + border-top: 1px solid var(--border); + background: #f8fbff; +} + +.footer-inner { + padding: 18px 0; + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; +} + +.footer-logo { + display: inline-flex; + margin-bottom: 8px; +} + +.footer-logo img { + width: clamp(231px, 25vw, 336px); + height: auto; + object-fit: contain; + transform: translateX(-18px); +} + +.mobile-sticky-cta { + display: none; +} + +@media (max-width: 1040px) { + .hero-grid, + .pricing-grid, + .cards, + .benefits-grid, + .two-col, + .cards.two { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .benefits-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (max-width: 760px) { + body { + background: + radial-gradient(circle at 12% -8%, #d4fff6 0, transparent 45%), + radial-gradient(circle at 88% 0%, #ffe7c2 0, transparent 38%), + var(--bg); + } + + .container { + width: min(1140px, 94vw); + } + + .hero { + padding: 16px 0 24px; + } + + .topbar { + flex-direction: column; + align-items: start; + gap: 12px; + margin-bottom: 20px; + } + + .brand img { + width: clamp(231px, 62vw, 336px); + transform: translateX(-12px); + } + + .nav { + flex-wrap: nowrap; + overflow-x: auto; + width: 100%; + padding-bottom: 4px; + scrollbar-width: thin; + } + + .nav a { + white-space: nowrap; + background: #ffffffb3; + border: 1px solid var(--border); + border-radius: 999px; + padding: 7px 12px; + font-size: 0.92rem; + } + + .phone { + background: var(--surface); + border: 1px solid var(--border); + padding: 9px 12px; + border-radius: 10px; + } + + .hero-grid, + .pricing-grid, + .cards, + .cards.two, + .two-col, + .benefits-grid { + grid-template-columns: 1fr; + } + + .price-card.featured { + transform: none; + } + + h1 { + font-size: clamp(1.6rem, 8vw, 2.1rem); + margin: 12px 0; + } + + h2 { + font-size: clamp(1.35rem, 7vw, 1.8rem); + } + + .lead { + font-size: 0.98rem; + } + + .cta-row { + gap: 10px; + } + + .btn { + width: 100%; + text-align: center; + padding: 13px 16px; + } + + .hero-card, + .card, + .price-card, + .panel, + .lead-form, + .faq-list details { + border-radius: 14px; + box-shadow: 0 8px 22px rgba(17, 32, 49, 0.08); + } + + .section { + padding: 32px 0; + } + + .cards, + .pricing-grid, + .faq-list { + gap: 12px; + } + + .lead-form { + gap: 9px; + padding: 14px; + } + + .footer-inner { + flex-direction: column; + align-items: start; + padding-bottom: 84px; + } + + .footer-logo img { + width: clamp(210px, 56vw, 315px); + transform: translateX(-10px); + } + + .mobile-sticky-cta { + position: fixed; + left: 12px; + right: 12px; + bottom: 12px; + display: block; + text-align: center; + text-decoration: none; + background: linear-gradient(90deg, var(--brand), #22a88f); + color: #fff; + font-weight: 800; + padding: 14px 16px; + border-radius: 12px; + box-shadow: 0 10px 28px rgba(11, 105, 92, 0.35); + z-index: 999; + } +} diff --git a/static/img/infrait-logo.png b/static/img/infrait-logo.png new file mode 100644 index 0000000..5834f22 Binary files /dev/null and b/static/img/infrait-logo.png differ diff --git a/static/js/main.js b/static/js/main.js new file mode 100644 index 0000000..7e10227 --- /dev/null +++ b/static/js/main.js @@ -0,0 +1,23 @@ +(() => { + const revealItems = document.querySelectorAll('.card, .price-card, .panel, .benefits-grid article, .faq-list details'); + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.style.opacity = '1'; + entry.target.style.transform = 'translateY(0)'; + observer.unobserve(entry.target); + } + }); + }, + { threshold: 0.08 } + ); + + revealItems.forEach((item, index) => { + item.style.opacity = '0'; + item.style.transform = 'translateY(18px)'; + item.style.transition = `opacity .45s ease ${index * 0.03}s, transform .45s ease ${index * 0.03}s`; + observer.observe(item); + }); +})(); diff --git a/templates/admin_login.html b/templates/admin_login.html new file mode 100644 index 0000000..d22c9ad --- /dev/null +++ b/templates/admin_login.html @@ -0,0 +1,27 @@ + + + + + + Вход в админку | InfraIT + + + + + + +
+
+

Админка InfraIT

+

Введите пароль администратора.

+
+ {% if error %} +

{{ error }}

+ {% endif %} + + +
+
+
+ + diff --git a/templates/admin_settings.html b/templates/admin_settings.html new file mode 100644 index 0000000..a9c8b34 --- /dev/null +++ b/templates/admin_settings.html @@ -0,0 +1,77 @@ + + + + + + Настройки сайта | InfraIT + + + + + + +
+
+
+
+

Личный кабинет администратора

+

Редактирование контактов, SEO и интеграций.

+
+ Выйти +
+ +
+ {% if success %} +

Настройки сохранены.

+ {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..9f5a482 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,37 @@ + + + + + + {% block title %}{{ settings.company_name }} — IT-аутсорсинг для бизнеса{% endblock %} + + + + + + + + + {% if settings.yandex_metrika_id %} + + + {% endif %} + + + + + {% block head_extra %}{% endblock %} + + + {% block content %}{% endblock %} + + {% block scripts %}{% endblock %} + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..e55da57 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,339 @@ +{% extends "base.html" %} + +{% block title %}{{ settings.company_name }} — IT-обслуживание бизнеса в Татарстане и по России{% endblock %} + +{% block head_extra %} + + +{% endblock %} + +{% block content %} +
+
+ + +
+
+ IT-аутсорсинг для бизнеса 5-100 ПК +

Комплексное IT-обслуживание компьютеров, серверов и сетей для стабильной работы бизнеса

+

Берём на себя всю IT-часть: от поддержки пользователей до серверов и резервного копирования. Дополнительно обеспечиваем поставку лицензионного ПО и мягкую миграцию на отечественные решения без остановки работы.

+ + + +
+ География: {{ settings.geo_primary }}. {{ settings.geo_secondary }}. +
+
+ + +
+
+
+ +
+
+
+

Услуги IT-обслуживания

+

Мы берём на себя всю IT-часть, чтобы бизнес работал без простоев.

+
+

Рабочие станции Windows/macOS

Настройка, обслуживание, обновления, контроль лицензий и производительности.

+

Поддержка пользователей

Удалённая помощь и выезды по Татарстану, чтобы сотрудники не теряли рабочее время.

+

Серверы и сервисы

Поддержка AD, файловых и прикладных серверов, контроль стабильности и доступа.

+

Сети и Wi-Fi

Администрирование сетевой инфраструктуры, сегментация, защита и оптимизация.

+

VPN и удалённая работа

Безопасный доступ сотрудников к корпоративным ресурсам из любой точки.

+

Резервное копирование

Настройка бэкапов и регулярная проверка восстановления данных.

+

Мониторинг инфраструктуры

Постоянный контроль серверов, сетей и критичных узлов с превентивным реагированием.

+

Модернизация IT-систем

Плановые обновления оборудования и ПО без остановки бизнес-процессов.

+

IT-консалтинг и планирование

Понятный план развития инфраструктуры под задачи и бюджет компании.

+

Поставка лицензионного ПО

Подбираем, закупаем и внедряем софт для бизнеса: ОС, офисные пакеты, безопасность, серверные лицензии.

+

Миграция на отечественные решения

Переход на российское ПО поэтапно: аудит, пилот, перенос данных, обучение сотрудников и сопровождение.

+
+
+
+ +
+
+

Тарифы обслуживания

+

Стоимость зависит от количества компьютеров: чем больше парк, тем ниже цена за 1 ПК.

+
+
+

Лайт

+

Для офисов 5-10 ПК

+

от 2 500 ₽ / ПК

+
    +
  • Удалённая поддержка пользователей
  • +
  • Базовое администрирование сети
  • +
  • Установка и обновление ПО
  • +
  • Консультации по рабочим вопросам
  • +
+ Выбрать Лайт +
+ + + +
+

Про

+

Для 30+ ПК и критичных систем

+

индивидуально

+
    +
  • Приоритетная поддержка
  • +
  • Расширенная стратегия бэкапов
  • +
  • SLA с фиксированными метриками
  • +
  • IT-планирование и аудит рисков
  • +
  • Повышенный уровень безопасности
  • +
  • Миграция на отечественное ПО под ключ
  • +
+ Обсудить Про +
+
+

Точная стоимость рассчитывается после короткого аудита: учитываем количество ПК, серверов, филиалов и требования к доступности.

+
+
+ +
+
+

Выгоды для бизнеса

+
+

Меньше простоев

Проблемы решаются до того, как превращаются в остановку работы отдела или офиса.

+

Понятные расходы

Ежемесячный бюджет на IT прогнозируем и не зависит от внезапных инцидентов.

+

Безопасность данных

Регламенты доступа, резервные копии и контроль восстановления снижают риски потерь.

+

Нет зависимости от одного человека

С вами работает команда, а не один администратор, недоступный в отпуске или на больничном.

+

IT развивается вместе с компанией

Инфраструктура масштабируется под рост штата, филиалов и новых бизнес-задач.

+
+
+
+ +
+
+
+

Почему аутсорсинг выгоднее штатного администратора

+
    +
  • Команда экспертов по цене одного специалиста
  • +
  • Закрываем и пользователей, и серверы, и сети
  • +
  • Нет затрат на налоги, отпускные и найм
  • +
  • Закупаем и сопровождаем нужное ПО без лишних подрядчиков
  • +
  • Фиксированный договор и прозрачные KPI
  • +
+
+
+

Как мы работаем

+
    +
  1. Аудит: изучаем инфраструктуру, риски и узкие места.
  2. +
  3. Обслуживание: запускаем регулярную поддержку и контроль.
  4. +
  5. Развитие: планируем и внедряем улучшения под рост бизнеса.
  6. +
+
+
+
+
+

После заключения договора

+

Критически важные системы подключаем к нашему мониторингу. При сбоях мы узнаем о проблеме сразу, моментально начинаем работы и оперативно уведомляем заказчика о статусе и сроках восстановления.

+
+
+
+ +
+
+

Дополнительные услуги

+

Усиливают защиту и устойчивость бизнеса, но не перегружают вашу операционку.

+
+
+

Соответствие ФЗ-152 (персональные данные)

+
    +
  • Аудит IT-инфраструктуры и процессов хранения данных
  • +
  • Рекомендации по защите и разграничению доступа
  • +
  • Практические шаги для снижения риска штрафов
  • +
+

Подключается как отдельная услуга без лишней бюрократии.

+
+ +
+

Переход на отечественное ПО

+
    +
  • Аудит текущего программного стека
  • +
  • Подбор российских аналогов под ваши задачи
  • +
  • Пилот, миграция и сопровождение команды
  • +
+

Помогаем перейти спокойно и без остановки работы.

+
+
+
+
+ +
+
+

SEO-блок для Яндекс: IT-аутсорсинг в Казани и Татарстане

+

InfraIT оказывает услуги IT-аутсорсинга для малого и среднего бизнеса: обслуживание компьютеров, серверов, сетей и корпоративных сервисов. Если вам нужно IT-обслуживание в Казани или по Татарстану с выездом инженера в день запроса, мы берём задачу в работу оперативно. Для компаний из других регионов России предоставляем удалённую IT-поддержку, мониторинг и администрирование с прозрачным SLA.

+

Мы работаем с офисами, бухгалтериями, юридическими фирмами, торговыми и сервисными компаниями, где важны стабильность, безопасность и предсказуемые расходы на IT. Отдельно сопровождаем поставку программного обеспечения и внедряем отечественные аналоги, чтобы бизнес соответствовал требованиям и развивался без технических рисков.

+
+
+ +
+
+

FAQ для руководителей

+
+
+ Сколько стоит IT-обслуживание в месяц? +

Цена зависит от количества компьютеров и состава инфраструктуры. Базово: чем больше ПК, тем ниже цена за единицу. Предварительный расчёт делаем после короткого интервью.

+
+
+ Насколько быстро вы подключаетесь к инцидентам? +

Большинство заявок берём в работу в течение 15-30 минут. Для критичных задач на тарифе Про действуют приоритетные регламенты и SLA.

+
+
+ Можно ли работать без выездов, только удалённо? +

Да. Для клиентов по России предоставляем полностью удалённый формат. {{ settings.geo_primary }}.

+
+
+ Вы можете взять инфраструктуру "под ключ"? +

Да, это наш основной формат. От поддержки сотрудников до серверов, сетей, бэкапов и развития IT.

+
+
+ Помогаете с поставкой ПО и переходом на российские решения? +

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

+
+
+
+
+ +
+
+
+

Оставьте заявку

+

Рассчитаем стоимость обслуживания и предложим формат поддержки под ваш бизнес за 30 минут.

+ +
+ +
+ {% if success %} +

Спасибо! Заявка отправлена. Мы свяжемся с вами в ближайшее время.

+ {% endif %} + {% if error %} +

{{ error }}

+ {% endif %} + + + + + + + + + +
+
+
+
+ +Рассчитать стоимость + + +{% endblock %}