Недавно случайно узнал, что BitBucket, где лежат мои Mercurial-репозитории, прекращает поддержку Mercurial: новые репозитории создавать уже нельзя, а существующие будут удалелы с 1.06.2020. Возможные варианты действий: перейти на Git, выбрать один из других сервисов, или настроить хостинг Mercurial на своём сервере. Сервер у меня есть, отказываться от Mercurial и менять привычки как-то не хочется, альтернативы BitBucket мне тоже не приглянулись — поэтому выбрал последний вариант. Задача вроде несложная, вот только сервер у меня под Windows, и, кажется, в процессе настройки я умудрился наступить на максимум возможных граблей. Надеюсь, эта статья поможет кому-нибудь избежать этого и сэкономить время. Различные варианты организации Mercurial-хостинга описаны в документации. Их можно разделить на 3 группы: Наиболее простым и логичным выглядит 1-й вариант. Как гласит документация, в Mercurial имеется встроенный веб-сервер, исполняющий HgWeb — именно он и работает, когда мы запускаем hg serve. Этот сервер не умеет делать аутентификацию, т.е. не умеет запрашивать логин/пароль пользователя, однако умеет делать авторизацию, т.е. давать/не давать тот или иной вид доспупа к репозиториям в соответствии с настройками доступа. Если нам нужны приватные репозитории, то для аутентификации можно использовать Nginx в качестве прокси-сервера, который будет запрашивать пароль. Настройка такой схемы описана здесь.  Для удобства hg serve запускается в виде сервиса с помощью winsw — утилиты, позволяющей запускать в виде сервиса любую команду (в данном случае это вообще bat-файл). Впрочем, для запуска можно обойтись и без сервиса, а, например, создать таск в Task Scheduler с триггером "At system startup" — такой таск будет запускаться при старте системы. Но это менее надёжный вариант: в случае сбоя таск не будет перезапущен, да и в логах информации об этом не будет. Будьте внимательны с файлами конфигурации (hgweb.conf / hgrc): Ещё обратите внимание на то, что Mercurial делает push в репозиторий одним запросом, и если ваш проект не "Hello world", то этот запрос может быть объёмным и длительным. Пропишите в конфиге Nginx достаточно большие значения: чтобы не оказаться в ситуации, когда вроде бы всё работает, а залить реальный проект на сервер не получается. В hgweb.conf задаётся общая для всех репозиториев конфигурация. Если нужны специфические настройки для каждого репозитория (а они нужны), то они указываются внутри репозитория: /.hg/hgrc Там можно, например, перечислить конкретных пользователей, имеющих доступ к данному репозиторию.  Чтобы это работало, Mercurial должен знать имя пользователя, который авторизовался в Nginx. И тут возникает проблема: на практике Mercurial видит всех пользователей, которых пропускает к нему Nginx одинаково безымянными. В различных источниках рекомендуют в конфигурации Nginx передавать имя пользователя в заголовках так: или так: но у меня это не сработало :( Судя по коду HgWeb, имя пользователя берется из ENV('REMOTE_USER'), но вот как его туда поместить — загадка. Если сложная авторизация не требуется, можно настроить её непосредственно в конфигурации Nginx либо создать 2 (или более) экземпляров hg serve, использующих различные файлы hgweb.conf. Недостаток в гибкости последнего метода в том, что настройки hgweb.conf глобальны и касаются всех (перечисленных в нем) репозиториев. Впрочем, комбинируя эти два метода можно добиться практически любых схем авторизации. В конце статьи я ещё коснусь этой темы. Описанные выше манипуляции попахивают извращением, поэтому я решил попробовать официальный Python-скрипт HgWeb. В бинарном дистрибутиве Mercurial его нет, поэтому нужно скачать дистрибутив исходников и взять оттуда. Там, кроме основной (CGI) версии, имеются также более эффективные — WSGI и FCGI.  Поскольку Nginx не умеет запускать CGI, а для WSGI нужен WSGI-сервер (поставить который на Windows отдельная проблема), я решил использовать FCGI — то есть FastCGI. Для его запуска нужен Python, причём документация гласит, что Python должен быть такой же версии, какая используется в бинарном дистрибутиве Mercurial — то есть 2.7. Окей, установил 2.7. Для запуска HgWeb в Python также необходимо установить библиотеку Flup, причём не просто установить, а определённой версии (ибо последняя не поддерживает Python 2.7). Вот так работает: Теперь нужно отредактировать сам hgweb.fcgi — прописать путь к файлу конфигурации (что очевидно) а также указать параметры запуска, как минимум обязательный параметр используемого локального адреса (что совершенно неочевидно): Осталось добавить конфигурацию Nginx: Я специально не редактировал файл fastcgi.conf, а вынес все дополнительные настройки fastcgi в секцию location для наглядности. Обратите внимание на параметр PATH_INFO — он важен для работы скрипта. В моём случае имя скрипта в url вообще отсутствует, а весь оставшийся путь идёт в PATH_INFO. Теперь запускаем сам скрипт:  и всё работает! Как и в случае с hg serve, разумно сделать запуск HgWeb в виде сервиса. Для этого использую всё тот же winsw. Он выполняет такой bat-файл: Обратите внимание, что я скопировал python.exe в python-hg.exe чтобы taskkill легко нашел единственный нужный процесс для остановки. Не стоит забывать и о безопасности: выполнять сервисы для публичного доступа под юзером "Local System" — плохая идея! Нужно создать отдельного юзера, дать ему доступ только к нужным папкам и запускать сервис под ним. Чтобы организовать публичный беспарольный доступ к некоторым репозиториям, документация рекомендует запускать два экземпляра HgWeb (или hg serve) с разными конфигурациями. Но можно сделать проще: для каждого репозитория, к которому нужен публичный доступ, добавить в конфигурацию Nginx отдельную секцию location без защиты паролем. Примерно так: Все — репозиторий Base доступен без пароля. Надеюсь, эта статья поможет вам сэкономить время. Лично у меня на всё это ушло примерно полтора дня (с учётом того, что Python я увидел, можно сказать, впервые в жизни :-) Indie Games Developer