Уровень: beginner → advanced
ОС сервера: Ubuntu 24.04 inside Oracle VM VirtualBox
Рекомендуемый IP сервера: 192.168.56.101
Дополнительная клиентская VM: Linux Mint, если на университетском Windows нет прав администратора
Базовый источник идеи: https://github.com/fa-python-network/5_FTP_server
В этой лабораторной работе студент создаёт собственный учебный файловый сервер на Python. Сервер работает по TCP, принимает текстовые команды от клиента, выполняет файловые операции внутри разрешённой папки и возвращает ответ.
Важно: это не промышленный FTP-сервер и не полная реализация официального FTP-протокола. Это учебная модель, которая помогает понять базовые принципы сетевой передачи файлов, клиент–серверного взаимодействия, авторизации, многопоточности и безопасной работы с путями файловой системы.
После этой лабораторной студенту будет намного проще понимать настоящие инструменты вроде scp, sftp, FTP-серверов, SSH, сетевых сокетов и серверной безопасности.
К концу LAB17 студент сможет:
- Объяснить модель client–server простыми словами.
- Написать TCP-сервер на Python с использованием модуля
socket. - Сделать сервер, который обслуживает несколько клиентов через
threading. - Реализовать команды файлового сервера:
help,pwd,ls,mkdir,rmdir,upload,download,cat,rename,rm,quit. - Понять, почему нужны разные порты для разных версий сервера.
- Проверять сервер через
nc, Python-клиент и Linux Mint VM. - Использовать
scpдля реальной передачи файлов между клиентом и сервером. - Предотвращать простую атаку directory traversal, например
../../etc/passwd. - Вести логирование действий сервера.
- Подготовить лабораторную работу как GitHub portfolio project.
В LAB17 есть 3 серверные программы. Они не должны работать на одном и том же порту, иначе возникнет ошибка Address already in use.
| Файл | Порт | Назначение |
|---|---|---|
basic_server.py |
9090 |
первый простой сервер для понимания TCP |
threaded_server.py |
9091 |
многопоточный сервер для нескольких клиентов |
ftp_server.py |
9092 |
финальный FTP-like сервер с авторизацией, логами и безопасными путями |
Проверить открытые порты можно так:
ss -tulnp | grep 909Если порт занят, остановите старую программу через Ctrl+C или найдите процесс:
sudo lsof -i :9092flowchart TB
subgraph ClientZone["Client side"]
C1["Ubuntu terminal\nusing nc"]
C2["Python smart_client.py"]
C3["Linux Mint VM\n192.168.56.102"]
C4["Windows PowerShell\nscp / ssh"]
end
subgraph ServerZone["Ubuntu Server VM - 192.168.56.101"]
B["basic_server.py\nTCP :9090"]
T["threaded_server.py\nTCP :9091"]
F["ftp_server.py\nTCP :9092"]
SSH["OpenSSH Server\nTCP :22"]
end
subgraph Storage["Server storage"]
W["server_workspace/public\nallowed file area"]
L["logs/server.log"]
end
C1 -->|"text command"| B
C1 -->|"text command"| T
C2 -->|"short commands"| F
C3 -->|"nc / python client"| F
C4 -->|"scp upload/download"| SSH
B --> W
T --> W
F --> W
F --> L
SSH --> W
sequenceDiagram
participant Client as Client / nc / smart_client
participant Server as ftp_server.py :9092
participant Parser as Command Parser
participant Auth as Auth Check
participant Safe as Safe Path Resolver
participant FS as Workspace Files
participant Log as logs/server.log
Client->>Server: upload student lab17 docs/hello.txt Hello
Server->>Parser: split command and arguments
Parser->>Auth: check username/password
Auth-->>Parser: OK
Parser->>Safe: resolve docs/hello.txt
Safe-->>Parser: allowed path inside workspace
Parser->>FS: write file content
Parser->>Log: record operation
Server-->>Client: OK uploaded: docs/hello.txt
Клиент может отправить опасный путь:
../../etc/passwd
Если сервер слепо откроет такой путь, пользователь сможет прочитать системные файлы. Поэтому финальный сервер использует Path.resolve() и проверяет, что итоговый путь остаётся внутри server_workspace/public.
flowchart LR
A["Client path"] --> B{"Path stays inside\nserver_workspace/public?"}
B -->|"Yes"| C["Allow operation"]
B -->|"No"| D["Reject: ERROR forbidden path"]
D --> E["Write security warning to log"]
Установите необходимые инструменты:
sudo apt update
sudo apt install python3 python3-venv python3-pip netcat-openbsd tree curl iproute2 net-tools openssh-server lsof -y
sudo systemctl enable --now sshПроверьте Python:
python3 --versionПроверьте IP сервера:
ip addr showДля VirtualBox Host-only Adapter в этой лабораторной ожидается:
192.168.56.101
Если у вас другой IP, используйте именно ваш адрес.
В этой версии лабораторной студент не клонирует готовый репозиторий. Он создаёт файлы сам, чтобы понять структуру проекта и назначение каждого файла.
Создайте папки:
mkdir -p ~/LAB17_FTP_SERVER
cd ~/LAB17_FTP_SERVER
mkdir -p server_workspace/public
mkdir -p client_downloads
mkdir -p logs
mkdir -p tests
mkdir -p screenshotsПроверьте структуру:
treeОжидаемо:
.
├── client_downloads
├── logs
├── screenshots
├── server_workspace
│ └── public
└── tests
Финальный сервер принимает одну команду на одно TCP-соединение. Это важно для понимания nc.
Формат команд с авторизацией:
command username password [arguments]
Данные для входа:
username: student
password: lab17
Правильные команды:
help
login student lab17
pwd student lab17
ls student lab17
mkdir student lab17 docs
upload student lab17 hello.txt Привет из клиента
download student lab17 hello.txt
rename student lab17 hello.txt message.txt
rm student lab17 message.txt
quit
Команда ниже открывает новое соединение, отправляет login, получает ответ и сразу закрывает соединение:
echo "login student lab17" | nc 127.0.0.1 9092Следующая команда снова откроет новое соединение. Поэтому сервер не помнит предыдущий login:
echo "mkdir docs" | nc 127.0.0.1 9092Поэтому при использовании nc нужно писать логин и пароль в каждой защищённой команде:
echo "mkdir student lab17 docs" | nc 127.0.0.1 9092Первый сервер нужен для начинающих. Он показывает главный принцип: клиент подключается к IP и порту, отправляет текст, сервер читает текст и возвращает ответ.
Создайте файл:
nano basic_server.pyВставьте код:
"""
LAB17 - Basic TCP File Server
Port: 9090
Purpose: first step for beginners. It accepts one command per TCP connection.
"""
import os
import socket
HOST = "0.0.0.0"
PORT = 9090
WORKSPACE = "server_workspace/public"
os.makedirs(WORKSPACE, exist_ok=True)
def process(request: str) -> str:
"""Process a small set of commands without authentication."""
request = request.strip()
if not request:
return "ERROR empty request"
if request == "help":
return "OK commands: help, pwd, ls, mkdir <folder>, quit"
if request == "quit":
return "OK goodbye"
if request == "pwd":
return "OK /"
if request == "ls":
items = os.listdir(WORKSPACE)
return "OK " + ("\n".join(items) if items else "empty directory")
if request.startswith("mkdir "):
folder_name = request.split(" ", 1)[1].strip()
if not folder_name:
return "ERROR folder name is required"
path = os.path.join(WORKSPACE, folder_name)
os.makedirs(path, exist_ok=True)
return f"OK folder created: {folder_name}"
return "ERROR unknown command"
def main() -> None:
print(f"Basic server is listening on {HOST}:{PORT}")
print(f"Workspace: {WORKSPACE}")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((HOST, PORT))
server.listen(5)
while True:
conn, addr = server.accept()
with conn:
print(f"Client connected: {addr}")
data = conn.recv(4096)
if not data:
conn.sendall(b"ERROR empty request")
continue
response = process(data.decode("utf-8", errors="replace"))
conn.sendall(response.encode("utf-8"))
if __name__ == "__main__":
main()Запустите сервер:
python3 basic_server.pyВ другом терминале проверьте:
echo "help" | nc 127.0.0.1 9090
echo "pwd" | nc 127.0.0.1 9090
echo "mkdir docs" | nc 127.0.0.1 9090
echo "ls" | nc 127.0.0.1 9090Обычный сервер обслуживает одного клиента за раз. В реальных системах несколько клиентов могут подключаться одновременно. Для этого мы используем threading: каждое подключение получает отдельный поток.
Создайте файл:
nano threaded_server.pyВставьте код из файла threaded_server.py финальной версии проекта или используйте готовый файл из пакета преподавателя.
Запустите:
python3 threaded_server.pyПроверьте:
echo "help" | nc 127.0.0.1 9091
echo "upload note.txt Hello from threaded server" | nc 127.0.0.1 9091
echo "cat note.txt" | nc 127.0.0.1 9091Для проверки нескольких клиентов откройте несколько терминалов и отправьте команды одновременно.
Финальный сервер добавляет важные профессиональные элементы:
- авторизация
student / lab17; - разные файловые команды;
- логирование в
logs/server.log; - безопасная обработка путей;
- многопоточность;
- понятные ответы
OKиERROR.
Создайте файл:
nano ftp_server.pyВставьте код из файла ftp_server.py финальной версии проекта.
Запустите сервер:
python3 ftp_server.pyПроверьте команды через nc:
echo "help" | nc 127.0.0.1 9092
echo "login student lab17" | nc 127.0.0.1 9092
echo "pwd student lab17" | nc 127.0.0.1 9092
echo "mkdir student lab17 docs" | nc 127.0.0.1 9092
echo "upload student lab17 docs/hello.txt Hello from Lab17" | nc 127.0.0.1 9092
echo "ls student lab17 docs" | nc 127.0.0.1 9092
echo "cat student lab17 docs/hello.txt" | nc 127.0.0.1 9092
echo "download student lab17 docs/hello.txt" | nc 127.0.0.1 9092
echo "rename student lab17 docs/hello.txt docs/message.txt" | nc 127.0.0.1 9092
echo "rm student lab17 docs/message.txt" | nc 127.0.0.1 9092Проверьте защиту от выхода за пределы рабочей папки:
echo "cat student lab17 ../../etc/passwd" | nc 127.0.0.1 9092Ожидаемый ответ:
ERROR forbidden path outside workspace
Если студент делает так:
echo "login student lab17" | nc 127.0.0.1 9092
echo "mkdir docs" | nc 127.0.0.1 9092вторая команда будет ошибочной, потому что это новое TCP-соединение. nc не хранит состояние между командами.
Правильно для nc:
echo "mkdir student lab17 docs" | nc 127.0.0.1 9092Правильно для smart_client.py:
login student lab17
mkdir docs
upload docs/note.txt This file was created from smart client
ls docs
cat docs/note.txt
Чтобы студенту не приходилось каждый раз писать student lab17, мы создаём умный клиент. Он принимает короткую команду, автоматически добавляет логин и пароль, отправляет команду серверу и показывает ответ.
Создайте файл:
nano smart_client.pyВставьте код из файла smart_client.py финальной версии проекта.
Запустите финальный сервер в одном терминале:
python3 ftp_server.pyВо втором терминале запустите клиента:
python3 smart_client.pyПример работы:
myftp@shell$ login student lab17
OK login successful
myftp@shell$ mkdir docs
OK folder created: docs
myftp@shell$ upload docs/note.txt This file was created from smart client
OK uploaded: docs/note.txt
myftp@shell$ ls docs
OK note.txt
myftp@shell$ cat docs/note.txt
OK
This file was created from smart client
myftp@shell$ save docs/note.txt local_note.txt
OK saved to client_downloads/local_note.txt
myftp@shell$ quit
OK goodbye
Client closed.
В университете студент может не иметь прав администратора на Windows-компьютере. Например, он не может редактировать hosts file или устанавливать некоторые инструменты. Поэтому удобно создать вторую VM с Linux Mint и использовать её как клиент.
Настройка:
| VM | Роль | Пример IP |
|---|---|---|
| Ubuntu 24.04 | сервер | 192.168.56.101 |
| Linux Mint | клиент | 192.168.56.102 |
На Linux Mint установите инструменты:
sudo apt update
sudo apt install netcat-openbsd python3 openssh-client -yПроверьте соединение:
ping 192.168.56.101Проверьте сервер:
echo "help" | nc 192.168.56.101 9092
echo "mkdir student lab17 from_mint" | nc 192.168.56.101 9092
echo "upload student lab17 from_mint/test.txt Hello from Linux Mint" | nc 192.168.56.101 9092
echo "cat student lab17 from_mint/test.txt" | nc 192.168.56.101 9092Если соединения нет, проверьте firewall на Ubuntu:
sudo ufw status
sudo ufw allow 9092/tcpscp это команда для безопасного копирования файлов между машинами через SSH. В отличие от нашего учебного TCP-сервера, scp использует OpenSSH, шифрование, системных пользователей Linux и порт 22.
Документация: https://man.openbsd.org/scp.1
Ubuntu OpenSSH Server: https://ubuntu.com/server/docs/openssh-server
На Ubuntu Server:
sudo systemctl status sshЕсли SSH не установлен:
sudo apt update
sudo apt install openssh-server -y
sudo systemctl enable --now sshПроверьте IP:
ip addr showНа Linux Mint создайте файл:
echo "Hello from Linux Mint client" > mint_upload.txtОтправьте файл на Ubuntu Server:
scp mint_upload.txt mohannad@192.168.56.101:/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/Замените mohannad на имя пользователя вашей Ubuntu VM.
На Ubuntu Server проверьте:
ls -l ~/LAB17_FTP_SERVER/server_workspace/public/
cat ~/LAB17_FTP_SERVER/server_workspace/public/mint_upload.txtНа Linux Mint выполните:
scp mohannad@192.168.56.101:/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/mint_upload.txt ./downloaded_from_server.txtПроверьте:
cat downloaded_from_server.txtОтправить папку:
scp -r my_folder mohannad@192.168.56.101:/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/Скачать папку:
scp -r mohannad@192.168.56.101:/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/my_folder ./my_folder_copyЕсли на Windows доступен OpenSSH Client, можно выполнить:
scp .\hello.txt mohannad@192.168.56.101:/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/Скачать файл:
scp mohannad@192.168.56.101:/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/hello.txt .\hello_downloaded.txtЕсли Windows не позволяет использовать нужные инструменты, используйте Linux Mint VM как клиент.
| Критерий | LAB17 FTP-like server | SCP |
|---|---|---|
| Протокол | учебный TCP protocol | SSH/SCP |
| Шифрование | нет | да |
| Пользователи | student/lab17 внутри кода |
реальные Linux users |
| Порт | 9092 |
22 |
| Цель | обучение socket/file protocol | реальная безопасная передача файлов |
| Безопасность | учебная защита путей | промышленный уровень через SSH |
Финальный сервер пишет логи в:
logs/server.logПроверить последние записи:
tail -n 20 logs/server.logПроверить security warning:
echo "cat student lab17 ../../etc/passwd" | nc 127.0.0.1 9092
tail -n 20 logs/server.logЗапустите финальный сервер:
python3 ftp_server.pyВ другом терминале выполните:
echo "help" | nc 127.0.0.1 9092
echo "login student lab17" | nc 127.0.0.1 9092
echo "mkdir student lab17 docs" | nc 127.0.0.1 9092
echo "upload student lab17 docs/final.txt Final LAB17 test" | nc 127.0.0.1 9092
echo "ls student lab17 docs" | nc 127.0.0.1 9092
echo "download student lab17 docs/final.txt" | nc 127.0.0.1 9092
echo "cat student lab17 ../../etc/passwd" | nc 127.0.0.1 9092Ожидаемые признаки успеха:
helpвозвращает список команд;loginвозвращаетOK login successful;mkdirсоздаёт папку;uploadсоздаёт файл;downloadвозвращает содержимое файла;- опасный путь возвращает ошибку безопасности.
Причина: порт уже занят.
Решение:
sudo lsof -i :9092Остановите старый процесс или используйте правильный порт.
Причина: сервер не запущен или выбран неправильный порт.
Проверьте:
python3 ftp_server.py
ss -tulnp | grep 9092Причина: команда требует логин и пароль.
Неправильно для nc:
echo "mkdir docs" | nc 127.0.0.1 9092Правильно:
echo "mkdir student lab17 docs" | nc 127.0.0.1 9092Проверьте:
ping 192.168.56.101
sudo ufw status
sudo ufw allow 9092/tcpТакже проверьте VirtualBox Network: обе VM должны быть в одной Host-only network.
Проверьте имя пользователя Ubuntu:
whoamiПроверьте SSH:
sudo systemctl status sshПроверьте путь назначения. Лучше использовать домашнюю папку пользователя, например:
/home/mohannad/LAB17_FTP_SERVER/server_workspace/public/В отчёт нужно добавить:
- Скриншот IP адреса Ubuntu Server.
- Скриншот запуска
basic_server.pyна порту9090. - Скриншот проверки
basic_server.pyчерезnc. - Скриншот запуска
threaded_server.pyна порту9091. - Скриншот запуска
ftp_server.pyна порту9092. - Скриншот успешного
upload/download. - Скриншот ошибки безопасности для
../../etc/passwd. - Скриншот работы
smart_client.py. - Скриншот SCP upload/download.
- Краткое объяснение: чем отличается учебный TCP file server от SCP.
| Критерий | Баллы |
|---|---|
| Создана структура проекта | 5 |
| Работает basic server на 9090 | 10 |
| Работает threaded server на 9091 | 10 |
| Работает final FTP-like server на 9092 | 20 |
| Реализованы файловые команды | 15 |
| Авторизация работает корректно | 10 |
| Защита от directory traversal | 10 |
| Smart client работает без повторного ввода логина в каждой команде | 10 |
| SCP upload/download выполнены | 5 |
| Отчёт со скриншотами и объяснениями | 5 |
| Итого | 100 |
- Python socket documentation: https://docs.python.org/3/library/socket.html
- Python threading documentation: https://docs.python.org/3/library/threading.html
- Python pathlib documentation: https://docs.python.org/3/library/pathlib.html
- OpenBSD scp manual: https://man.openbsd.org/scp.1
- Ubuntu OpenSSH Server guide: https://ubuntu.com/server/docs/openssh-server
- Original educational idea repository: https://github.com/fa-python-network/5_FTP_server
Эта лабораторная работа специально построена от простого к профессиональному:
- сначала студент понимает TCP;
- затем видит проблему нескольких клиентов;
- затем добавляет авторизацию и безопасные пути;
- затем сравнивает свой учебный сервер с реальным инструментом
scp.
Такой порядок помогает не просто копировать код, а понимать сетевую инженерию, Linux-практику и серверное программирование.