Upload 5 files
Browse files- Dockerfile +35 -0
- docker-compose.yml +15 -0
- supervisord.conf +22 -0
- vpn_server.py +42 -0
- web_ui.py +35 -0
Dockerfile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use a lightweight Python base image
|
| 2 |
+
FROM python:3.11-slim
|
| 3 |
+
|
| 4 |
+
# Set the working directory
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# Install the pvpn library, FastAPI, Uvicorn, and Supervisord
|
| 8 |
+
# Running as root for this step.
|
| 9 |
+
RUN apt-get update && \
|
| 10 |
+
apt-get install -y supervisor && \
|
| 11 |
+
pip install pvpn fastapi uvicorn python-multipart && \
|
| 12 |
+
apt-get clean && rm -rf /var/lib/apt/lists/*
|
| 13 |
+
|
| 14 |
+
# Ensure the working directory is writeable (though it is by default for root)
|
| 15 |
+
# This addresses the user's explicit request.
|
| 16 |
+
RUN chmod -R 777 /app
|
| 17 |
+
|
| 18 |
+
# The container will run as the default root user, which allows binding to
|
| 19 |
+
# privileged ports 500 and 4500 without needing setcap.
|
| 20 |
+
|
| 21 |
+
# Copy the server scripts and supervisord config
|
| 22 |
+
# No need for --chown as we are running as root
|
| 23 |
+
COPY vpn_server.py web_ui.py supervisord.conf .
|
| 24 |
+
|
| 25 |
+
# Expose the standard IKEv2 ports (UDP 500 and 4500)
|
| 26 |
+
EXPOSE 500/udp
|
| 27 |
+
EXPOSE 4500/udp
|
| 28 |
+
|
| 29 |
+
# Expose the Web UI port (TCP 8000)
|
| 30 |
+
EXPOSE 8000/tcp
|
| 31 |
+
|
| 32 |
+
RUN useradd -m -u 1000 user
|
| 33 |
+
USER user
|
| 34 |
+
# Command to run Supervisord, which manages both the IKEv2 server and the Web UI
|
| 35 |
+
CMD ["/usr/bin/supervisord", "-c", "supervisord.conf"]
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: '3.8'
|
| 2 |
+
services:
|
| 3 |
+
ikev2_server:
|
| 4 |
+
build: .
|
| 5 |
+
container_name: pure_python_ikev2_server
|
| 6 |
+
# Map the required UDP ports for IKEv2
|
| 7 |
+
ports:
|
| 8 |
+
- "500:500/udp"
|
| 9 |
+
- "4500:4500/udp"
|
| 10 |
+
# Map the TCP port for the Web UI
|
| 11 |
+
- "8000:8000/tcp"
|
| 12 |
+
# Add network administration capability for VPN
|
| 13 |
+
cap_add:
|
| 14 |
+
- NET_ADMIN
|
| 15 |
+
restart: always
|
supervisord.conf
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[supervisord]
|
| 2 |
+
nodaemon=true
|
| 3 |
+
|
| 4 |
+
[program:ikev2_server]
|
| 5 |
+
command=python3 vpn_server.py
|
| 6 |
+
autostart=true
|
| 7 |
+
autorestart=true
|
| 8 |
+
priority=10
|
| 9 |
+
stdout_logfile=/dev/stdout
|
| 10 |
+
stdout_logfile_maxbytes=0
|
| 11 |
+
stderr_logfile=/dev/stderr
|
| 12 |
+
stderr_logfile_maxbytes=0
|
| 13 |
+
|
| 14 |
+
[program:web_ui]
|
| 15 |
+
command=uvicorn web_ui:app --host 0.0.0.0 --port 8000
|
| 16 |
+
autostart=true
|
| 17 |
+
autorestart=true
|
| 18 |
+
priority=20
|
| 19 |
+
stdout_logfile=/dev/stdout
|
| 20 |
+
stdout_logfile_maxbytes=0
|
| 21 |
+
stderr_logfile=/dev/stderr
|
| 22 |
+
stderr_logfile_maxbytes=0
|
vpn_server.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import logging
|
| 3 |
+
from pvpn.server import main
|
| 4 |
+
|
| 5 |
+
# Configure basic logging
|
| 6 |
+
logging.basicConfig(level=logging.INFO, stream=sys.stdout,
|
| 7 |
+
format='%(asctime)s - %(levelname)s - %(message)s')
|
| 8 |
+
|
| 9 |
+
def start_ikev2_server_programmatically():
|
| 10 |
+
"""
|
| 11 |
+
Starts a pure Python IKEv2 server using the pvpn library.
|
| 12 |
+
|
| 13 |
+
This is designed to run inside a container where permissions
|
| 14 |
+
to bind to privileged ports (500/4500) have been pre-granted
|
| 15 |
+
to the Python executable via setcap.
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
# Arguments for the pvpn server
|
| 19 |
+
original_argv = sys.argv
|
| 20 |
+
sys.argv = [
|
| 21 |
+
"pvpn",
|
| 22 |
+
"-p", "MySecretPSK123", # The Pre-Shared Key
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
print("Starting pure Python IKEv2 VPN server...")
|
| 26 |
+
print("PSK: MySecretPSK123")
|
| 27 |
+
print("Listening on UDP ports 500 and 4500.")
|
| 28 |
+
|
| 29 |
+
try:
|
| 30 |
+
# The main function runs the asyncio loop and the server indefinitely
|
| 31 |
+
main()
|
| 32 |
+
except KeyboardInterrupt:
|
| 33 |
+
print("\nServer stopped by user.")
|
| 34 |
+
except Exception as e:
|
| 35 |
+
# Catching any unexpected errors during startup or runtime
|
| 36 |
+
print(f"An unexpected error occurred: {e}")
|
| 37 |
+
finally:
|
| 38 |
+
# Restore sys.argv
|
| 39 |
+
sys.argv = original_argv
|
| 40 |
+
|
| 41 |
+
if __name__ == '__main__':
|
| 42 |
+
start_ikev2_server_programmatically()
|
web_ui.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from fastapi.responses import HTMLResponse
|
| 3 |
+
|
| 4 |
+
app = FastAPI()
|
| 5 |
+
|
| 6 |
+
@app.get("/", response_class=HTMLResponse)
|
| 7 |
+
async def home():
|
| 8 |
+
html_content = """
|
| 9 |
+
<html>
|
| 10 |
+
<head>
|
| 11 |
+
<title>IKEv2 VPN Server Management</title>
|
| 12 |
+
</head>
|
| 13 |
+
<body>
|
| 14 |
+
<h1>Pure Python IKEv2 Server Status</h1>
|
| 15 |
+
<p>The IKEv2 server process is running alongside this Web UI.</p>
|
| 16 |
+
<p><strong>IKEv2 Status:</strong> Running (Managed by Supervisord)</p>
|
| 17 |
+
<p><strong>Web UI Port:</strong> TCP 8000 (Uvicorn)</p>
|
| 18 |
+
<p><strong>VPN Ports:</strong> UDP 500 & 4500 (pvpn)</p>
|
| 19 |
+
<h2>Connection Details</h2>
|
| 20 |
+
<ul>
|
| 21 |
+
<li><strong>PSK:</strong> MySecretPSK123</li>
|
| 22 |
+
<li><strong>URL:</strong> Your public URL</li>
|
| 23 |
+
</ul>
|
| 24 |
+
<hr>
|
| 25 |
+
<p>In a full implementation, this UI would show logs, connection counts, and allow configuration changes.</p>
|
| 26 |
+
</body>
|
| 27 |
+
</html>
|
| 28 |
+
"""
|
| 29 |
+
return html_content
|
| 30 |
+
|
| 31 |
+
@app.get("/status")
|
| 32 |
+
async def status():
|
| 33 |
+
# In a real app, this would check if the vpn_server process is alive
|
| 34 |
+
return {"status": "ok", "service": "Web UI", "vpn_server": "running (assumed)"}
|
| 35 |
+
|