Всем привет! Вчера я опубликовал статью о том, как настроить свой собственный VPN с помощью Outline и VPS. В конце статьи было голосование за тему программного взаимодействия с VPN через Python. Многие из вас выразили интерес, и вот продолжение специально для вас.
Для начала необходимо настроить VPN и получить ответ от вашего VPS сервера в следующем формате (данные вымышлены):
{"apiUrl":"https://000.86.000.204:22422/lvOQvrWWEOOfY9SSOBbgsesFP","certSha256":"AA26A5X1840FD23AD0F018550A5F9B7UHDA392D3da89EE0D08A1D5331KJF358"}
О том, как это сделать и зачем, вы можете прочитать в моей предыдущей статье. Для продолжения у нас должны быть:
Скачанная программа Outline Manager (для удобства тестирования)
Скачанная программа Outline Client (для проверки работоспособности ключей)
Установленный Python 3 (не ниже версии 3.8)
Если все это у вас есть, давайте запустим IDE и начнем писать код (я буду использовать PyCharm).
Сегодня мы напишем код по правилам, используя requirements.txt
и .env
.
Настраиваем файл .env:
API_URL=https://000.86.000.204:22422/lvOQvrWWEOOfY9SSOBbgsesFP
CERT_SHA=AA26A5X1840FD23AD0F018550A5F9B7UHDA392D3da89EE0D08A1D5331KJF358
Заполняем файл requirements.txt:
outline-vpn-api
python-decouple
Устанавливаем необходимые модули:
pip install -r requirements.txt
Описание установленных модулей:
outline-vpn-api
– это обертка вокругrequests
, настроенная для отправки запросов на сервера Outline. Можно было бы написать свою, но эта библиотека достаточно логична и понятна, так что не вижу смысла тратить время.
python-decouple
– модуль для работы с .env
. Я использую его давно, и он никогда меня не подводил, если вы привыкли к другой реализации - на ваше усмотрение.
Настраиваем файл config.py:
from decouple import config
from outline_vpn.outline_vpn import OutlineVPN
api_url = config('API_URL')
cert_sha256 = config('CERT_SHA')
client = OutlineVPN(api_url=api_url, cert_sha256=cert_sha256)
Здесь мы импортируем модуль для работы с .env
и объект класса OutlineVPN
. Далее настраиваем клиент для взаимодействия с Outline.
Файл main.py
Прежде чем приступить к написанию кода, немного поясню, чем мы будем заниматься.
Библиотека outline-vpn-api
достаточно проста, но я предлагаю написать еще одну обертку над ней, свою. Это поможет в случаях, когда задачи не стандартные, например, обработка данных на лету.
Импортируем нашего клиента из настроек:
from config import client
Пишем функцию для преобразования гигабайт в байты:
def gb_to_bytes(gb: float):
bytes_in_gb = 1024 ** 3 # 1 ГБ = 1024^3 байт
return int(gb * bytes_in_gb)
Эта функция нужна для преобразования гигабайтов в байты. Outline Manager позволяет устанавливать лимит на месячный трафик по ключу, и он передается только в байтах и только целым числом.
Получение информации о всех ключах:
def get_keys():
return client.get_keys()
Проходимся по ключам циклом и смотрим данные:
vpn_keys = get_keys()
for key in vpn_keys:
print(key)
Для доступа к информации из каждого отдельного ключа нужно использовать точку (на следующем примере мы это подробнее рассмотрим). Внутри можно найти такие данные:
key_id (строковый идентификатор айди, очень важный)
name (строка, имя ключа, иногда полезно, например, чтоб понимать какой ключ и под какое устройство или чей ключ)
access_url (строка, ключ для подключения к VPN)
used_bytes (использованное количество байтов)
data_limit (лимит на использование данных)
Password, port и method (в данной статье рассматривать не будем, достаточно специфическая информация)
Получение информации по конкретному ключу:
def get_key_info(key_id: str):
return client.get_key(key_id)
key_info = get_key_info("100")
print(key_info.access_url)
На примере выше мы получили не весь объект ключа, а конкретное значение (access_url), которое является самим ключом доступа к VPN.
Создание нового ключа:
def create_new_key(key_id: str = None, name: str = None, data_limit_gb: float = None):
return client.create_key(key_id=key_id, name=name, data_limit=gb_to_bytes(data_limit_gb))
Кроме тех параметров, что я передал, функция client.create_key
также может принимать: method
, password
и port
. Эти параметры мы рассмотрим в следующий раз, а сейчас давайте разберемся, что же принимает наша функция:
key_id – строковый айдишник, если оставить None, то будет по умолчанию присвоен айди такого вида «1» (числовая строка)
name – имя ключа (описывал выше зачем нужен параметр)
data_limit_gb – тут мы передаем в виде float значения количество ГБ, которое будет доступно пользователю на 1 месяц (выше уже написали функцию, которая будет переводить ГБ в байты)
Давайте создадим первый ключ с такими данными:
key_id = None (пусть сам Outline придумает айди)
name = «HabrKey»
data_limit_gb = 1.5
new_key_info = create_new_key(name='HabrKey', data_limit_gb=1.5)
print(new_key_info)
Отлично! Наш ключ создан. На скриншоте выше вы можете увидеть, что ключу было присвоено имя, которое мы передали, и задан лимит по данным. При этом key_id
был присвоен автоматически ("6"). Этот идентификатор понадобится нам для тестирования других функций.
Давайте посмотрим в программе Outline Manager создался ли наш ключ:
Мы видим, что ключ создан и лимит данных немного больше, чем мы указали (1.61 ГБ). Это связано с тем, что моя функция была намеренно упрощена. В качестве домашнего задания вы можете написать аналогичную функцию, которая будет точно преобразовывать любое значение в байты. Если у вас получится, поделитесь ею в комментариях.
Переименование ключа:
def rename_key(key_id: str, new_key_name: str):
return client.rename_key(key_id, new_key_name)
status_rename = rename_key(key_id='6', new_key_name='HabrKeyNewName')
print(status_rename)
Думаю тут все понятно. Передали идентификатор и новое имя. Давайте посмотрим что получилось:
Обновление лимита данных:
def upd_limit(key_id: str, data_limit_gb: float):
return client.add_data_limit(key_id, gb_to_bytes(data_limit_gb))
status_update = upd_limit(key_id='6', data_limit_gb=5)
print(status_update)
Эта функция предназначена для увеличения месячного лимита данных. В примере выше мы увеличили лимит до 5 ГБ. Проверяем:
Снова наблюдаем небольшое отклонение в объеме ГБ, но видим, что лимит успешно увеличен.
Снимаем лимит данных:
def delete_limit(key_id: str):
return client.delete_data_limit(key_id)
status_delete_limit = delete_limit(key_id='6')
print(status_delete_limit)
Эта функция полностью снимает ограничение на лимит по данным. Проверим:
Удаление ключа:
def delete_key(key_id: str):
return client.delete_key(key_id)
status_delete_key = delete_key("6")
print(status_delete_key)
Получение технической информации о сервере:
def get_service_info():
return client.get_server_information()
В библиотеке outline-vpn-api
есть и другие методы, но так как я пишу это руководство для тех, кто только знакомится с Outline, не вижу смысла перегружать информацией. Думаю, те, кому потребуется дополнительная функциональность, смогут разобраться самостоятельно.
Выводы
Несмотря на кажущуюся простоту программного взаимодействия с Outline, система достаточно мощная, удобная и гибкая. Рекомендую всем, как минимум, протестировать ее.
На этом пока все. Подписывайтесь – у меня для вас запасено много интересной информации. До скорого.
Комментарии (4)
Chupaka
10.06.2024 07:45bytes_in_gb = 1024 ** 3 # 1 ГБ = 1024^3 байт
И дальше по тексту видим, что всё же 1 ГБ = 1000^3 байт :)
salbey
Добрый день, расскажите про динамические ключи Outline. У меня не получилось сформировать по руководству.
yakvenalex Автор
Добрый день, что вы подразумеваете под "динамические ключи"?
salbey
Dynamic Access Keys — это функция в Outline Client, которая позволяет хранить информацию о доступе к VPN в удалённом месте и обновлять её динамически.
Это позволяет менять местоположение VPN, порт, пароль для доступа к нему и метод шифрования на лету без необходимости повторно выдавать ключи доступа всем пользователям.