В Python для этого есть встроенный модуль http.server, который позволяет развернуть сервер без установки сторонних библиотек (вроде Flask или Django). Этот модуль идеально подходит для таких задач, как:
Быстрого обмена файлами в локальной сети.
Тестирования простых HTML/JS страниц.
Создания "заглушек" (mock-серверов) для тестирования API.
Обучения основам HTTP-протокола.
В то же время стоит учитывать, http.server НЕ предназначен для полноценного использования в продакшене (Production) в виду некоторых ограничений безопасности.
В реальности при создании http-сервера нам даже не нужно никакого программного кода - http.server можно вызвать напрямую из командной строки, используя опцию -m
интерпретатора в следующем формате:
python -m http.server [OPTIONS] [port]
Поэтому если цель http-сервера - просто "раздать" файлы из текущей папки, то достаточно открыть терминал и ввести:
python -m http.server
По умолчанию HTTP-сервер запускается по адресу http://127.0.0.1:8000/. И если мы откроем браузер и введем этот адрес, то увидим список файлов из папки, где была запущена команда.
eugene@Eugene:~/python/httpserver$ ls -l total 5 -rwxrwxrwx 1 root root 1138 Nov 10 16:54 app.py -rwxrwxrwx 1 root root 140 Aug 17 11:55 hello.txt -rwxrwxrwx 1 root root 140 Aug 17 11:55 test.py eugene@Eugene:~/python/httpserver$ python3 -m http.server Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 127.0.0.1 - - [07/Dec/2025 22:22:49] "GET / HTTP/1.1" 200 -
Рассмотрим, какие параметры можно передать при запуске сервера:
port
По умолчанию сервер прослушивает порт 8000. Значение по умолчанию можно переопределить, передав нужный номер порта в качестве аргумента:
python -m http.server 9000
-b, --bind [адрес]
Указывает конкретный адрес, к которому следует привязаться. Поддерживаются адреса IPv4 и IPv6. По умолчанию сервер привязывается ко всем интерфейсам. Например, следующая команда заставляет сервер привязываться только к localhost:
python -m http.server --bind 127.0.0.1
-d, --directory [Каталог]
Указывает на используемый каталог. По умолчанию сервер использует текущий каталог. Например, следующая команда использует определённый каталог:
python -m http.server --directory /tmp/
-p, --protocol [версия]
Указывает версию HTTP, с которой совместим сервер. По умолчанию сервер совместим с HTTP/1.0. Например, следующая команда запускает сервер, совместимый с HTTP/1.1:
python -m http.server --protocol HTTP/1.1
--tls-cert
Задаёт цепочку сертификатов TLS для HTTPS-подключений:
python -m http.server --tls-cert fullchain.pem
--tls-key
Задаёт файл закрытого ключа для HTTPS-подключений. Для этого параметра требуется указать --tls-cert.
--tls-password-file
Задаёт файл паролей для закрытых ключей, защищённых паролем:
python -m http.server \ --tls-cert cert.pem \ --tls-key key.pem \ --tls-password-file password.txt
Для программного создания HTTP-сервера в модуле http.server определены следующие классы:
HTTPServer: подкласс класса socketserver.TCPServer, по сути обертка над сокетом, применяемый для создания простого HTTP-сервера
ThreadingHTTPServer: идентичен HTTPServer, но использует потоки для обработки запросов
HTTPSServer: подкласс HTTPServer с использованием модуля ssl. Если модуль SSL недоступен, создание экземпляра объекта HTTPServer завершается с ошибкой RuntimeError.
ThreadingHTTPSServer: идентичен HTTPSServer, но использует потоки для обработки запросов аналогично ThreadingHTTPServer, только с использованием HTTPSServer.
При создании экземпляра этих классов в конструктор передается объект
socketserver.StreamRequestHandler. В модуле http.server для определены три его подкласса:
BaseHTTPRequestHandler: используется для обработки HTTP-запросов, поступающих на сервер. Он также предоставляет ряд переменных класса и экземпляра, а также методов для использования подклассами.
SimpleHTTPRequestHandler : обслуживает файлы из файловой системы, напрямую сопоставляя структуру каталога с HTTP-запросами.
CGIHTTPRequestHandler: используется для обслуживания файлов или вывода сценариев CGI из текущего каталога и ниже.
Возьмем самый простой класс - HTTPServer
class http.server.HTTPServer(server_address, RequestHandlerClass)
Этот класс HTTPServer наследуется от класса socketserver.TCPServer, который представляет функциональность tcp-сервера. Через первый параметр этот класс получает адрес сервера - собственно адрес и сетевой порт и сохраняет их в переменных server_name и server_port.
Второй параметр - RequestHandlerClass представляет обработчик запросов - именно через него мы и определяем, что делать, если пришел запрос.
Рассмотрим самый простейший пример обработки запросов. Используем в качестве обработчика самый простой класс обработчика - BaseHTTPRequestHandler
class http.server.BaseHTTPRequestHandler(request, client_address, server)
Пусть наш веб-сервер просто будет отправлять некоторое сообщение в ответ. Для этого определим следующий скрипт:
from http.server import HTTPServer, BaseHTTPRequestHandler
# Класс-обработчик входящих запросов
class MyHandler(BaseHTTPRequestHandler):
# обработка get-запросов
def do_GET(self):
# 1. Отправляем код ответа (200 = OK)
self.send_response(200)
# 2. Отправляем заголовки (headers)
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
# 3. Отправляем тело ответа
self.wfile.write("Hello METANIT.COM".encode("utf-8"))
# Настройки запуска
hostName = "localhost"
serverPort = 8000
# Инициализация сервера
webServer = HTTPServer((hostName, serverPort), MyHandler)
print(f"Сервер запущен: http://{hostName}:{serverPort}")
try:
# Бесконечный цикл прослушивания порта
webServer.serve_forever()
except KeyboardInterrupt:
# остановка по Ctrl+C
print("Работа сервера прервана")
webServer.server_close()
print("Сервер остановлен...")
Рассмотрим код. Предже всего мы определяем обработчик запросов - подкласс BaseHTTPRequestHandler, который пусть называется MyHandler:
class MyHandler(BaseHTTPRequestHandler):
# обработка get-запросов
def do_GET(self):
# 1. Отправляем код ответа (200 = OK)
self.send_response(200)
# 2. Отправляем заголовки (headers)
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
# 3. Отправляем тело ответа
self.wfile.write("Hello METANIT.COM".encode("utf-8"))
Пусть наш обработчик обрабатывает только базовые - GET-запросы. Для обработки таких запросов в классе надо определить метод do_GET(). Причем это самая минимально необходимая схема обработки запросов,
еоторая состоит из трех частей. Сначала с помощью метода send_response() отправляет статусный код ответа:
self.send_response(200)
Далее нам надо указать клиенту, какой тип ответа отправляется:
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
Стоит отметить, что вызов self.end_headers() необходим, чтобы заголовки, отправленные через self.send_header(), реально отправились, а не остались в буфере.
В данном случае будем рассматривать ответ как код html в кодировке "utf-8".
В конце отправляем собственно тело ответа с помощью метода self.wfile.write():
self.wfile.write("Hello METANIT.COM".encode("utf-8"))
self.wfile - это "файл записи": все, что записывается сюда, отправится обратно клиенту (браузеру). Однако сеть работает с байтами, и в метод self.wfile.write() передается набор байтов.
Поэтому для отправки строка преобразуется в набор байтов с помощью вызова encode("utf-8")
Далее устанавливаем настройки запуска - будем запускать локально на порту 8000:
hostName = "localhost" serverPort = 8000
Далее инициализируем объект сервера, передавая в него адрес запуска и класс обработчика запросов:
webServer = HTTPServer((hostName, serverPort), MyHandler)
Далее в конструкции try..except запускаем сервер и начинаем прослушивать входящие запросы:
try:
# Бесконечный цикл прослушивания порта
webServer.serve_forever()
except KeyboardInterrupt:
# остановка по Ctrl+C
print("Работа сервера прервана")
webServer.server_close()
Поскольку HTTPServer - подкласс socketserver.TCPServer, то соответственно наследует его методы для работы с запросами. Например, для запуска и прослушивания входящих
запросов применяется унаследованный метод serve_forever(). А для завершения сервера и освобождения ресурсов используется унаследованный метод server_close()
Стоит учитывать, что метод serve_forever() фактически запускает бесконечный цикл для прослушивания входящих запрос. И чтобы выйти из этого цикла в консоли можно применить стандартное сочетание клавиш Ctrl+C.
Поэтому в конструкции try..except с помощью отслеживания исключения KeyboardInterrupt, мы можем отловить нажатие этих клавиш и выполнить некоторые действия - в
данном случае просто выводим уведомление на консоль.
И после завершения прослушивания запросов завершаем работу сервера, выполняя метод server_close()
Запустим скрипт на выполнение (в моем случае это файл app.py):
eugene@Eugene:~/python/httpserver$ python3 app.py Сервер запущен: http://localhost:8000
Перейдем по адресу "http://localhost:8000" в браузере:
При обращении по адресу наш http-сервер получит запрос и отправит в ответ строку. Тем временем консоль все это запротоколирует:
eugene@Eugene:~/python/httpserver$ python3 app.py Сервер запущен: http://localhost:8000 127.0.0.1 - - [08/Dec/2025 16:05:49] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [08/Dec/2025 16:05:49] "GET /favicon.ico HTTP/1.1" 200 -
Для выхода из сервера нажмем Ctrl+C (Ctrl+Alt+C):
eugene@Eugene:~/python/httpserver$ python3 app.py Сервер запущен: http://localhost:8000 127.0.0.1 - - [08/Dec/2025 16:05:49] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [08/Dec/2025 16:05:49] "GET /favicon.ico HTTP/1.1" 200 - ^CРабота сервера прервана Сервер остановлен... eugene@Eugene:~/python/httpserver$