Данный материал составлен в рамках подготовки ответа на вопрос - "а как нам опубликовать свой api в 1С?" для моего хорошего друга Егора. Приведён пример публикации с полным, мне известным набором опций, некоторые из которых можно выключить. Например, пароль пользователя 1C зашит в vrd файл, чтобы упростить работу сторонним разработчикам. Для авторизации используется механизм клиентских HTTPs сертификатов в виде p12 файлов, которые подходят для авторизации тонких клиентов.
1С
Прилагаю к публикации файл с базой, c развёрнутыми сервисами.
В целом, это вся настройка:

Код ни на что не претендует, выдернул из того, что было (это весь)
Функция ОбработатьЗапрос(Запрос)
ИмяМетода = Запрос.ПараметрыURL.Получить("Method");
Ответ = Новый HTTPСервисОтвет(400);
Если ИмяМетода = "test" Тогда
Ответ.КодСостояния = 202;
ИначеЕсли ИмяМетода = "GetTables" Тогда
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(ОбработкаAPI.ВернутьТаблицы(Запрос.ПараметрыЗапроса), КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
ИначеЕсли ИмяМетода = "GetFile" Тогда
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-type", "application/any; charset=utf-8");
Ответ.Заголовки.Вставить("Content-Disposition", "attachment; filename=" + "file.txt");
Ответ.УстановитьТелоИзДвоичныхДанных(ПолучитьДвоичныеДанныеФайла(Запрос.ПараметрыЗапроса));
ИначеЕсли ИмяМетода = "TakeJSON" Тогда
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Запрос.ПолучитьТелоКакСтроку());
ПринятыеДанные = ПрочитатьJSON(ЧтениеJSON,,,ФорматДатыJSON.ISO);
ЧтениеJSON.Закрыть();
СтруктураОтвета = Новый Структура;
Для каждого КиЗ ИЗ ПринятыеДанные Цикл
СтруктураОтвета.Вставить(КиЗ.Ключ,"1337");
КонецЦикла;
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(ОбработкаAPI.ВернутьJSONСОписаниемДат(СтруктураОтвета), КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Иначе
Ответ.КодСостояния = 405;
Результат = "Отсутствует Метод " + ИмяМетода;
КонецЕсли;
Возврат Ответ;
КонецФункции // ОбработатьЗапрос()
Функция ПолучитьДвоичныеДанныеФайла(ПараметрыЗапроса) Экспорт
Поток = новый ПотокВПамяти();
Запись = новый ЗаписьДанных(Поток,КодировкаТекста.UTF8);
Запись.ЗаписатьСимволы("Тестовый текстовый файл");
Запись.Закрыть();
Возврат Поток.ЗакрытьИПолучитьДвоичныеДанные();
//Файл = Справочники.МойСправочник.ПолучитьСсылку(Новый УникальныйИдентификатор(ПараметрыЗапроса["uid"]));
//Возврат Новый ДвоичныеДанные(ПутьКФайлу);
КонецФункции // ПолучитьДвоичныеДанныеФайла()
//Функция ВернутьДанныеТаблиц(ДатаНачала,ДатаОкончания,Поставщик)
Функция ВернутьДанныеТаблиц()
#Область ТестовыеТаблицы
Таблица1 = Новый ТаблицаЗначений;
Таблица1.Колонки.Добавить("Номер");
Таблица1.Колонки.Добавить("Дата");
Таблица1.Колонки.Добавить("Комментарий");
НС = Таблица1.Добавить();
НС.Номер = 1;
НС.Дата = Дата(2026,01,01);
НС.Комментарий = "С Новым годом!";
НС = Таблица1.Добавить();
НС.Номер = 2;
НС.Дата = Дата(2026,02,17);
НС.Комментарий = "С Китайским новым годом!";
Таблица2 = Новый ТаблицаЗначений;
Таблица2.Колонки.Добавить("Номер");
Таблица2.Колонки.Добавить("ДатаДоговора");
Таблица2.Колонки.Добавить("Комментарий");
НС = Таблица2.Добавить();
НС.Номер = "1111-000001";
НС.ДатаДоговора = Дата(2025,12,14);
НС.Комментарий = "С Ханукой!";
#КонецОбласти
Рез = Новый Структура();
Рез.Вставить("Таблица1", ОбщегоНазначенияТаблицаЗначенийВМассив(Таблица1));
Рез.Вставить("Таблица2", ОбщегоНазначенияТаблицаЗначенийВМассив(Таблица2));
Рез.Вставить("ОписаниеДат","Дата,ДатаДоговора");
//ЗаменитьСсылкуНаУИД(Рез.ТаблицаИнвойсов,"Ссылка");
//ЗаменитьСсылкуНаУИД(Рез.Контейнеры,"Ссылка");
//ЗаменитьСсылкуНаУИД(Рез.Услуги,"Ссылка");
Возврат Рез;
КонецФункции
Функция ВернутьТаблицы(ПараметрыЗапроса) Экспорт
//ТГП = ВернутьДанныеТаблиц(ВернутьДату(ПараметрыЗапроса["ds"]),ВернутьДату(ПараметрыЗапроса["de"]),Число(ПараметрыЗапроса["supp"]));
ТГП = ВернутьДанныеТаблиц();
Возврат ВернутьJSONСОписаниемДат(Новый Структура("Таблица1,Таблица2",ТГП.Таблица1,ТГП.Таблица2),ТГП.ОписаниеДат);
КонецФункции
Функция ВернутьJSONСОписаниемДат(Значение,ПереченьПолейСДатами=Неопределено) Экспорт
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Значение);
СтрокаДЖ = ЗаписьJSON.Закрыть();
Если ПереченьПолейСДатами=Неопределено Тогда
Возврат СтрокаДЖ;
КонецЕсли;
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON,Новый Структура("ПереченьПолейСДатами,Значение",ПереченьПолейСДатами,СтрокаДЖ),СтандартныеНастройкиСериализацииJSON());
Возврат ЗаписьJSON.Закрыть();
КонецФункции // ВернутьJSONСОписанием()
Функция СтандартныеНастройкиСериализацииJSON() Экспорт
НС = Новый НастройкиСериализацииJSON;
НС.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.ЛокальнаяДата;
НС.ФорматСериализацииДаты = ФорматДатыJSON.ISO;
Возврат НС;
КонецФункции
Процедура ЗаменитьСсылкуНаУИД(ТЗ,КолонкиЧерезЗапятую)
Колонки = СтрРазделить(КолонкиЧерезЗапятую,",");
Для каждого Строка ИЗ ТЗ Цикл
Для каждого Колонка из Колонки Цикл
Строка[Колонка] = ?(ЗначениеЗаполнено(Строка[Колонка]),Строка(Строка[Колонка].УникальныйИдентификатор()),"00000000-0000-0000-0000-000000000000");
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Функция ВернутьДату(СтрД) // 01-01-2025
Возврат Дата(Прав(СтрД,4),Сред(СтрД,4,2),Лев(СтрД,2));
КонецФункции // ВернутьДату()
Функция ОбщегоНазначенияТаблицаЗначенийВМассив(ТаблицаЗначений)
Массив = Новый Массив();
СтруктураСтрокой = "";
НужнаЗапятая = Ложь;
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
Если НужнаЗапятая Тогда
СтруктураСтрокой = СтруктураСтрокой + ",";
КонецЕсли;
СтруктураСтрокой = СтруктураСтрокой + Колонка.Имя;
НужнаЗапятая = Истина;
КонецЦикла;
Для Каждого СтрокаТаблицы Из ТаблицаЗначений Цикл
НоваяСтрока = Новый Структура(СтруктураСтрокой);
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТаблицы);
Массив.Добавить(НоваяСтрока);
КонецЦикла;
Возврат Массив;
КонецФункции
Apache
Загрузите Apache, разместите Apache24 на цэ диске (можно в другом месте, необходимо изменить SRVROOT)
Приведённые ниже пути, относительны C:\Apache24
сonf/httpd.conf
# === Основные настройки ===
Define SRVROOT "C:/Apache24"
ServerRoot ${SRVROOT}
Listen 4453
ServerAdmin admin@example.org
ServerName terminal.example.org
# === Размер тела запроса (100MB) ===
LimitRequestBody 104857600
# === Поддержка Keep-Alive для долгих запросов 1С ===
KeepAlive On
MaxKeepAliveRequests 1000
KeepAliveTimeout 300
Timeout 600
# === Настройки ядра ===
AcceptFilter https none
AcceptFilter http none
EnableSendfile Off
EnableMMAP Off
# === Загрузка необходимых модулей ===
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule dir_module modules/mod_dir.so
LoadModule env_module modules/mod_env.so
LoadModule include_module modules/mod_include.so
LoadModule isapi_module modules/mod_isapi.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule _1cws_module "C:/Program Files/1cv8/8.3.27.1859/bin/wsap24.dll"
LoadModule headers_module modules/mod_headers.so
LoadModule alias_module modules/mod_alias.so
# === Корневая директория ===
DocumentRoot "${SRVROOT}/htdocs"
<Directory "${SRVROOT}/htdocs">
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# === Запрет доступа к системным файлам ===
<Files ".ht*">
Require all denied
</Files>
<DirectoryMatch "^.*/\..+">
Require all denied
</DirectoryMatch>
# === Логи ===
ErrorLog "logs/error.log"
LogLevel warn
CustomLog "logs/access.log" common
# === SSL ===
<IfModule ssl_module>
SSLEngine On
SSLCertificateFile conf/certs/cert.pem
SSLCertificateKeyFile conf/certs/key.pem
SSLCACertificateFile conf/certs/ca.crt
SSLProtocol -all +TLSv1.2
SSLCipherSuite HIGH:!aNULL:!MD5
SSLHonorCipherOrder On
#SSLOpenSSLConfCmd CertificateVerification require
SSLSessionCache "shmcb:${SRVROOT}/logs/ssl_scache(2048000)"
SSLSessionCacheTimeout 300
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
CustomLog "${SRVROOT}/logs/ssl_request.log" \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" env=HTTPS
</IfModule>
# === Публикация базы 1С ===
Alias "/post4egor" "bases/post4egor"
<Directory "bases/post4egor">
AllowOverride None
Options None
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "bases/post4egor/default.vrd"
#Header set Cache-Control "no-store, no-cache, must-revalidate"
#Header set Pragma "no-cache"
SSLVerifyClient require
SSLRequire %{SSL_CLIENT_S_DN_CN} eq "Apache1CPub"
</Directory>
# === Индексный файл ===
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
bases/post4egor/default.vrd
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/post4egor"
ib="Srvr="onec";Ref="post4egor";usr="1CAPIUser";pwd="keef9yooy3Ze1itiexie";">
<httpServices publishByDefault="false">
<service name="Api"
rootUrl="api"
enable="true"
reuseSessions="autouse"
sessionMaxAge="60"
poolSize="20"
poolTimeout="10">
</service>
</httpServices>
</point>
Сертификат web-сервера
Выпуск самоподписанного сертификата
openssl req -x509 -nodes -days 3650 -newkey rsa:3072 \
-keyout key.pem \
-out cert.pem \
-subj "/C=RU/ST=Moscow/L=Moscow/O=Company/OU=IT/CN=localhost"
Только для ознакомления. Не используйте самоподписанные сертификаты в бою
Сертификат центра сертификации
Им будут подписаны клиентские сертификаты
openssl req -new -newkey rsa:3072 -nodes -keyout ca.key -x509 -days 3650 \
-subj "/C=RU/ST=Msk/L=Msk/O=MyOrg/OU=MyUnit/CN=IT/emailAddress=usr@localhost" \
-out ca.crt
Клиентские сертификаты
Методика выпуска подробно изложена в великолепной, нестареющей статье https://www.opennet.ru/base/sec/ssl_cert.txt.html
К публикации приложен файл Template.tar.bz2, в котором подготовлен каталог по методике из этой статьи (Только для unix-подобных систем)
В этом каталоге необходимо выполнить предыдущую команду по выпуску CA, и выпустить сам сертификат:
./create_cert ORGUNIT COMPANY VASYA PASS
Для примера выпустим сертификат Apache1CPub без пароля:
./create_cert IT Apache1CPub Apache1CPub
ls -l ./db/certs/Apache1CPub/Apache1CPub/
итого 22
-rw-r--r-- 1 root root 4617 янв 23 10:48 Apache1CPub.crt
-rw-r--r-- 1 root root 1037 янв 23 10:48 Apache1CPub.csr
-rw------- 1 root root 1704 янв 23 10:48 Apache1CPub.key
-rw------- 1 root root 3885 янв 23 10:48 Apache1CPub.p12
Для подключения достаточно p12 файла. После его установки стандартными средствами Win/Mac/Android, доступ будет получен в большинстве браузеров. Так же, подходит для использования тонким клиентом:

Запуск
Поместите в каталог conf/certs/ файлы key.pem,cert.pem,ca.crt
Откройте командную строку от имени администратора, перейдите в C:\Apache\bin, установите службу.
cd C:\Apache24\bin
httpd.exe -k install -n "Apache1CPubService"
Проверяем в браузере локально:
https://localhost:4453/post4egor/hs/api/v1/GetTables
Проверка
Файл p12 должен находиться в рабочей директории
curl -X POST \
--cert-type P12 \
--cert ./Apache1CPub.p12 \
--pass "" \
-H "Content-Type: application/json" \
-d '{"key": "value"}' \
-k \
"https://apachehost:4453/post4egor/hs/api/v1/TakeJSON"
curl -X GET \
--cert-type P12 \
--cert ./Apache1CPub.p12 \
--pass "" \
-k \
"https://apachehost:4453/post4egor/hs/api/test/"
Буду рад всем комментариям, надеюсь найти ошибки и пробелы в знаниях, в особенности в части составления httpd.conf для 1С, так как нечто цельное пока на глаза не попадалось. Этот файл готовил с помощью ЫЫ.
Вступайте в нашу телеграмм-группу Инфостарт
