|
1 | | -import uvicorn |
2 | | -from app import app |
3 | | -from config import ( |
4 | | - DEBUG, |
5 | | - UVICORN_HOST, |
6 | | - UVICORN_PORT, |
7 | | - UVICORN_UDS, |
8 | | - UVICORN_SSL_CERTFILE, |
9 | | - UVICORN_SSL_KEYFILE |
10 | | -) |
| 1 | +import click |
11 | 2 | import logging |
| 3 | +import os |
| 4 | +import ssl |
| 5 | + |
| 6 | +import uvicorn |
| 7 | +from cryptography import x509 |
| 8 | +from cryptography.hazmat.backends import default_backend |
| 9 | + |
| 10 | +from app import app, logger |
| 11 | +from config import (DEBUG, UVICORN_HOST, UVICORN_PORT, UVICORN_SSL_CERTFILE, |
| 12 | + UVICORN_SSL_KEYFILE, UVICORN_UDS) |
| 13 | + |
| 14 | + |
| 15 | +def validate_cert_and_key(cert_file_path, key_file_path): |
| 16 | + if not os.path.isfile(cert_file_path): |
| 17 | + raise ValueError(f"SSL certificate file '{cert_file_path}' does not exist.") |
| 18 | + if not os.path.isfile(key_file_path): |
| 19 | + raise ValueError(f"SSL key file '{key_file_path}' does not exist.") |
| 20 | + |
| 21 | + try: |
| 22 | + context = ssl.create_default_context() |
| 23 | + context.load_cert_chain(certfile=cert_file_path, keyfile=key_file_path) |
| 24 | + except ssl.SSLError as e: |
| 25 | + raise ValueError(f"SSL Error: {e}") |
| 26 | + |
| 27 | + try: |
| 28 | + with open(cert_file_path, 'rb') as cert_file: |
| 29 | + cert_data = cert_file.read() |
| 30 | + cert = x509.load_pem_x509_certificate(cert_data, default_backend()) |
| 31 | + |
| 32 | + if cert.issuer == cert.subject: |
| 33 | + raise ValueError("The certificate is self-signed and not issued by a trusted CA.") |
| 34 | + |
| 35 | + except Exception as e: |
| 36 | + raise ValueError(f"Certificate verification failed: {e}") |
| 37 | + |
12 | 38 |
|
13 | 39 | if __name__ == "__main__": |
14 | 40 | # Do NOT change workers count for now |
15 | 41 | # multi-workers support isn't implemented yet for APScheduler and XRay module |
| 42 | + |
| 43 | + bind_args = {} |
| 44 | + |
| 45 | + if UVICORN_SSL_CERTFILE and UVICORN_SSL_KEYFILE: |
| 46 | + validate_cert_and_key(UVICORN_SSL_CERTFILE, UVICORN_SSL_KEYFILE) |
| 47 | + |
| 48 | + bind_args['ssl_certfile'] = UVICORN_SSL_CERTFILE |
| 49 | + bind_args['ssl_keyfile'] = UVICORN_SSL_KEYFILE |
| 50 | + |
| 51 | + if UVICORN_UDS: |
| 52 | + bind_args['uds'] = UVICORN_UDS |
| 53 | + else: |
| 54 | + bind_args['host'] = UVICORN_HOST |
| 55 | + bind_args['port'] = UVICORN_PORT |
| 56 | + |
| 57 | + else: |
| 58 | + if UVICORN_UDS: |
| 59 | + bind_args['uds'] = UVICORN_UDS |
| 60 | + else: |
| 61 | + |
| 62 | + logger.warning(f""" |
| 63 | +{click.style('IMPORTANT!', blink=True, bold=True, fg="yellow")} |
| 64 | +You're running Marzban without specifying {click.style('UVICORN_SSL_CERTFILE', italic=True, fg="magenta")} and {click.style('UVICORN_SSL_KEYFILE', italic=True, fg="magenta")}. |
| 65 | +The application will only be accessible through localhost. This means that {click.style('Marzban and subscription URLs will not be accessible externally', bold=True)}. |
| 66 | +
|
| 67 | +If you need external access, please provide the SSL files to allow the server to bind to 0.0.0.0. Alternatively, you can run the server on localhost or a Unix socket and use a reverse proxy, such as Nginx or Caddy, to handle SSL termination and provide external access. |
| 68 | +
|
| 69 | +If you wish to continue without SSL, you can use SSH port forwarding to access the application from your machine. note that in this case, subscription functionality will not work. |
| 70 | +
|
| 71 | +Use the following command: |
| 72 | +
|
| 73 | +{click.style(f'ssh -L {UVICORN_PORT}:localhost:{UVICORN_PORT} user@server', italic=True, fg="cyan")} |
| 74 | +
|
| 75 | +Then, navigate to {click.style(f'http://127.0.0.1:{UVICORN_PORT}', bold=True)} on your computer. |
| 76 | + """) |
| 77 | + |
| 78 | + bind_args['host'] = '127.0.0.1' |
| 79 | + bind_args['port'] = UVICORN_PORT |
| 80 | + |
| 81 | + if DEBUG: |
| 82 | + bind_args['uds'] = None |
| 83 | + bind_args['host'] = '0.0.0.0' |
| 84 | + |
16 | 85 | try: |
17 | 86 | uvicorn.run( |
18 | 87 | "main:app", |
19 | | - host=('0.0.0.0' if DEBUG else UVICORN_HOST), |
20 | | - port=UVICORN_PORT, |
21 | | - uds=(None if DEBUG else UVICORN_UDS), |
22 | | - ssl_certfile=UVICORN_SSL_CERTFILE, |
23 | | - ssl_keyfile=UVICORN_SSL_KEYFILE, |
| 88 | + **bind_args, |
24 | 89 | workers=1, |
25 | 90 | reload=DEBUG, |
26 | 91 | log_level=logging.DEBUG if DEBUG else logging.INFO |
|
0 commit comments