new format
This commit is contained in:
parent
542334d914
commit
2e94156ffe
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
MIT License Copyright (c) <year> <copyright holders>
|
MIT License Copyright (c) 2021 quackerd
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
"inbounds": [
|
"inbounds": [
|
||||||
{
|
{
|
||||||
"port": 1080,
|
"port": {{ port }},
|
||||||
"listen": "127.0.0.1",
|
"listen": "127.0.0.1",
|
||||||
"protocol": "socks",
|
"protocol": "socks",
|
||||||
"sniffing": {
|
"sniffing": {
|
||||||
@ -88,12 +88,12 @@
|
|||||||
"settings": {
|
"settings": {
|
||||||
"vnext": [
|
"vnext": [
|
||||||
{
|
{
|
||||||
"address": "{{ server_name }}",
|
"address": "{{ subdomain }}.{{ domain }}",
|
||||||
"port": 443,
|
"port": 443,
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"id": "{{ uuid }}",
|
"id": "{{ id }}",
|
||||||
"alterId": 64,
|
"alterId": {{ alterid }},
|
||||||
"security": "none"
|
"security": "none"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -104,7 +104,7 @@
|
|||||||
"network": "ws",
|
"network": "ws",
|
||||||
"security": "tls",
|
"security": "tls",
|
||||||
"wsSettings": {
|
"wsSettings": {
|
||||||
"path": "/{{ path }}"
|
"path": "{{ path }}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -119,4 +119,4 @@
|
|||||||
"tag": "block"
|
"tag": "block"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
4
client_obj.in
Normal file
4
client_obj.in
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"id": "{{ id }}",
|
||||||
|
"alterId": {{ alterid }}
|
||||||
|
}
|
32
config.yml
Normal file
32
config.yml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
server:
|
||||||
|
# the domain name
|
||||||
|
domain: domain.tld
|
||||||
|
# the subdomain name. leave empty for naked domain.
|
||||||
|
subdomain: example
|
||||||
|
# email. your email for the registered SSL cert. leave empty for a dummy email.
|
||||||
|
email:
|
||||||
|
# the user/group to run the docker-compose stack.
|
||||||
|
# defaults to the current user
|
||||||
|
# or you can manually set, e.g.:
|
||||||
|
# uid: 1000
|
||||||
|
# gid: 1000
|
||||||
|
uid:
|
||||||
|
gid:
|
||||||
|
# the path for websocket. Do NOT include the leading slash. default: auto-generated.
|
||||||
|
path:
|
||||||
|
# whether or not to enable watchtower to auto update docker containers. default: false
|
||||||
|
watchtower: False
|
||||||
|
|
||||||
|
clients:
|
||||||
|
- name: example_user1
|
||||||
|
# default id: auto-generated uuid
|
||||||
|
id:
|
||||||
|
# default alterid: 64
|
||||||
|
alterid:
|
||||||
|
# port for local socks5. default: 1080
|
||||||
|
port:
|
||||||
|
- name: example_user2
|
||||||
|
# or you can set them manually
|
||||||
|
id: 5058b990-6be5-438d-9c02-4b06b5d927d0
|
||||||
|
alterid: 32
|
||||||
|
port: 6666
|
176
configure.py
Normal file
176
configure.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import uuid
|
||||||
|
import pwd
|
||||||
|
import jinja2
|
||||||
|
import random
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
OUTPUT_DIR = "build"
|
||||||
|
CLIENT_OUTPUT_DIR = "clients"
|
||||||
|
DEFAULT_EMAIL = "dummy@dummy.org"
|
||||||
|
CONF_FILE = "config.yml"
|
||||||
|
SERVER_IN = "server.in"
|
||||||
|
SERVER_PATH = "v2ray"
|
||||||
|
SERVER_FN = "config.json"
|
||||||
|
NGINX_IN = "nginx.in"
|
||||||
|
NGINX_PATH = "nginx/nginx/site-confs"
|
||||||
|
NGINX_FN = "default"
|
||||||
|
DEFAULT_ALTERID = 64
|
||||||
|
CLIENT_OBJ_IN = "client_obj.in"
|
||||||
|
CLIENT_CONF_IN = "client_conf.in"
|
||||||
|
DOCKER_IN = "docker-compose.in"
|
||||||
|
WATCHTOWER_IN = "watchtower.in"
|
||||||
|
DEFAULT_WATCHTOWER_ENABLE = False
|
||||||
|
DEFAULT_CLIENT_PORT = 1080
|
||||||
|
|
||||||
|
def yaml_key_exists_else(mapping : [], name : str, other_val = None, nullable = True):
|
||||||
|
if (name in mapping) and (mapping[name] != None):
|
||||||
|
return mapping[name]
|
||||||
|
else:
|
||||||
|
if not nullable:
|
||||||
|
raise Exception("Key " + name + " must not be null.")
|
||||||
|
else:
|
||||||
|
return other_val
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
def __init__(self, conf_obj):
|
||||||
|
self.name = str(yaml_key_exists_else(conf_obj, 'name', nullable=False))
|
||||||
|
self.id = str(yaml_key_exists_else(conf_obj, 'id', other_val=uuid.uuid4()))
|
||||||
|
self.alterid = int(yaml_key_exists_else(conf_obj,'alterid', other_val=DEFAULT_ALTERID))
|
||||||
|
self.port = int(yaml_key_exists_else(conf_obj, 'port', other_val=DEFAULT_CLIENT_PORT))
|
||||||
|
|
||||||
|
def print(self, ident):
|
||||||
|
pre = ""
|
||||||
|
for i in range(ident):
|
||||||
|
pre += " "
|
||||||
|
|
||||||
|
print(pre + "{")
|
||||||
|
print(pre + " id: " + self.id)
|
||||||
|
print(pre + " alterid: " + str(self.alterid))
|
||||||
|
print(pre + " port: " + str(self.port))
|
||||||
|
print(pre + "}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
@staticmethod
|
||||||
|
def __randomString(stringLength=16):
|
||||||
|
letters = string.ascii_lowercase
|
||||||
|
return ''.join(random.choice(letters) for i in range(stringLength))
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
print("Server configuration:")
|
||||||
|
print(" domain: " + self.domain)
|
||||||
|
print(" email: " + self.email)
|
||||||
|
print(" subdomain: " + self.subdomain)
|
||||||
|
print(" uid: " + str(self.uid))
|
||||||
|
print(" gid: " + str(self.gid))
|
||||||
|
print(" path: " + self.path)
|
||||||
|
print(" clients:")
|
||||||
|
for i in range(len(self.clients)):
|
||||||
|
self.clients[i].print(8)
|
||||||
|
|
||||||
|
def __init__(self, f):
|
||||||
|
conf = yaml.safe_load(f)
|
||||||
|
conf_srv = conf['server']
|
||||||
|
|
||||||
|
self.domain = str(yaml_key_exists_else(conf_srv, 'domain', nullable=False))
|
||||||
|
self.email = str(yaml_key_exists_else(conf_srv, 'email', other_val=DEFAULT_EMAIL))
|
||||||
|
self.subdomain = str(yaml_key_exists_else(conf_srv, 'subdomain', other_val=""))
|
||||||
|
self.subdomain_only = len(self.subdomain) == 0
|
||||||
|
self.uid = int(yaml_key_exists_else(conf_srv, 'uid', other_val=os.getuid()))
|
||||||
|
self.gid = int(yaml_key_exists_else(conf_srv, 'gid', other_val=os.getgid()))
|
||||||
|
self.path = str(yaml_key_exists_else(conf_srv, 'path', other_val=self.__randomString()))
|
||||||
|
self.watchtower = bool(yaml_key_exists_else(conf_srv, 'watchtower', other_val=DEFAULT_WATCHTOWER_ENABLE))
|
||||||
|
|
||||||
|
self.clients = []
|
||||||
|
conf_clients = conf['clients']
|
||||||
|
for i in range(len(conf_clients)):
|
||||||
|
self.clients.append(Client(conf_clients[i]))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(CONF_FILE, 'r') as f:
|
||||||
|
conf = Config(f)
|
||||||
|
conf.print()
|
||||||
|
|
||||||
|
template_dict = {}
|
||||||
|
template_dict['uid'] = conf.uid
|
||||||
|
template_dict['gid'] = conf.gid
|
||||||
|
template_dict['subdomain'] = conf.subdomain
|
||||||
|
template_dict['subdomain_only'] = conf.subdomain_only
|
||||||
|
template_dict['domain'] = conf.domain
|
||||||
|
template_dict['email'] = conf.email
|
||||||
|
template_dict['path'] = conf.path
|
||||||
|
|
||||||
|
if conf.watchtower:
|
||||||
|
with open(WATCHTOWER_IN, "r") as f:
|
||||||
|
template_dict['watchtower'] = f.read()
|
||||||
|
else:
|
||||||
|
template_dict['watchtower'] = ""
|
||||||
|
|
||||||
|
clients = ""
|
||||||
|
with open(CLIENT_OBJ_IN, "r") as f:
|
||||||
|
client_obj = f.read()
|
||||||
|
for i in range(len(conf.clients)):
|
||||||
|
if i > 0:
|
||||||
|
clients += ",\n"
|
||||||
|
clients += jinja2.Template(client_obj).render(id = conf.clients[i].id,
|
||||||
|
alterid = conf.clients[i].alterid)
|
||||||
|
template_dict['clients'] = clients
|
||||||
|
|
||||||
|
print("Generating files...")
|
||||||
|
|
||||||
|
# create output dir
|
||||||
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
# generate docker-compose.yml
|
||||||
|
path = os.path.join(OUTPUT_DIR, "docker-compose.yml")
|
||||||
|
with open(DOCKER_IN, "r") as f:
|
||||||
|
template = jinja2.Template(f.read())
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write(template.render(template_dict))
|
||||||
|
|
||||||
|
# generate NGINX conf
|
||||||
|
with open(NGINX_IN, "r") as f:
|
||||||
|
template = jinja2.Template(f.read())
|
||||||
|
path = os.path.join(OUTPUT_DIR, NGINX_PATH)
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
|
path = os.path.join(path, NGINX_FN)
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write(template.render(template_dict))
|
||||||
|
|
||||||
|
# generate v2ray conf
|
||||||
|
with open(SERVER_IN, "r") as f:
|
||||||
|
template = jinja2.Template(f.read())
|
||||||
|
path = os.path.join(OUTPUT_DIR, SERVER_PATH)
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
|
path = os.path.join(path, SERVER_FN)
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write(template.render(template_dict))
|
||||||
|
|
||||||
|
# generate client confs
|
||||||
|
path = os.path.join(OUTPUT_DIR, CLIENT_OUTPUT_DIR)
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
|
with open(CLIENT_CONF_IN, "r") as f:
|
||||||
|
client_conf_temp = jinja2.Template(f.read())
|
||||||
|
for i in range(len(conf.clients)):
|
||||||
|
template_dict['id'] = conf.clients[i].id
|
||||||
|
template_dict['port'] = conf.clients[i].port
|
||||||
|
template_dict['alterid'] = conf.clients[i].alterid
|
||||||
|
epath = os.path.join(path, conf.clients[i].name + "_" + conf.clients[i].id)
|
||||||
|
os.makedirs(epath, exist_ok=True)
|
||||||
|
with open(os.path.join(epath, SERVER_FN), "w") as f:
|
||||||
|
f.write(client_conf_temp.render(template_dict))
|
||||||
|
|
||||||
|
# chown
|
||||||
|
os.chown(OUTPUT_DIR, conf.uid, conf.gid)
|
||||||
|
for dirpath, dirnames, filenames in os.walk(OUTPUT_DIR):
|
||||||
|
os.chown(dirpath, conf.uid, conf.gid)
|
||||||
|
for fname in filenames:
|
||||||
|
os.chown(os.path.join(dirpath, fname), conf.uid, conf.gid)
|
||||||
|
print("Please find the generated files in the build directory. To start the stack, run docker-compose up -d in the build directory.")
|
||||||
|
|
||||||
|
main()
|
@ -1,18 +1,18 @@
|
|||||||
version: '3.4'
|
version: '3.0'
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
lan:
|
br-v2ray:
|
||||||
external: false
|
external: false
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
container_name: nginx
|
container_name: v2ray_nginx
|
||||||
image: linuxserver/letsencrypt
|
image: linuxserver/letsencrypt
|
||||||
restart: always
|
restart: unless-stopped
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
networks:
|
networks:
|
||||||
- lan
|
- br-v2ray
|
||||||
environment:
|
environment:
|
||||||
- PUID={{ uid }}
|
- PUID={{ uid }}
|
||||||
- PGID={{ gid }}
|
- PGID={{ gid }}
|
||||||
@ -20,9 +20,9 @@ services:
|
|||||||
- URL={{ domain }}
|
- URL={{ domain }}
|
||||||
- SUBDOMAINS={{ subdomain }}
|
- SUBDOMAINS={{ subdomain }}
|
||||||
- VALIDATION=http
|
- VALIDATION=http
|
||||||
- EMAIL={{ email }}
|
- EMAIL=dummy@dummy.com
|
||||||
- DHLEVEL=2048
|
- DHLEVEL=2048
|
||||||
- ONLY_SUBDOMAINS={{ only_sub }}
|
- ONLY_SUBDOMAINS={{ subdomain_only }}
|
||||||
- STAGING=false
|
- STAGING=false
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
@ -31,11 +31,13 @@ services:
|
|||||||
- ./nginx:/config
|
- ./nginx:/config
|
||||||
|
|
||||||
v2ray:
|
v2ray:
|
||||||
container_name: v2ray
|
container_name: v2ray_v2ray
|
||||||
image: teddysun/v2ray
|
image: teddysun/v2ray
|
||||||
restart: always
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- lan
|
- br-v2ray
|
||||||
command: ["v2ray","-config=/etc/v2ray/config.json"]
|
command: ["v2ray","-config=/etc/v2ray/config.json"]
|
||||||
volumes:
|
volumes:
|
||||||
- ./v2ray:/etc/v2ray
|
- ./v2ray:/etc/v2ray
|
||||||
|
|
||||||
|
{{ watchtower }}
|
@ -1,5 +0,0 @@
|
|||||||
d example.com
|
|
||||||
s v2ray
|
|
||||||
e email@domain.tld
|
|
||||||
u 00000000-0000-0000-0000-000000000000
|
|
||||||
p somepath
|
|
@ -17,10 +17,10 @@ server {
|
|||||||
# all ssl related config moved to ssl.conf
|
# all ssl related config moved to ssl.conf
|
||||||
include /config/nginx/ssl.conf;
|
include /config/nginx/ssl.conf;
|
||||||
|
|
||||||
server_name {{server_name}};
|
server_name {{ subdomain }}.{{ domain }};
|
||||||
location /{{ path }} {
|
location /{{ path }} {
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_pass http://v2ray:8080;
|
proxy_pass http://v2ray_v2ray:8080;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
@ -6,10 +6,7 @@
|
|||||||
"protocol": "vmess",
|
"protocol": "vmess",
|
||||||
"settings": {
|
"settings": {
|
||||||
"clients": [
|
"clients": [
|
||||||
{
|
{{ clients }}
|
||||||
"id": "{{ uuid }}",
|
|
||||||
"alterId": 64
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"streamSettings": {
|
"streamSettings": {
|
||||||
@ -26,4 +23,4 @@
|
|||||||
"settings": {}
|
"settings": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
158
setup.py
158
setup.py
@ -1,158 +0,0 @@
|
|||||||
import getopt
|
|
||||||
import sys
|
|
||||||
import uuid
|
|
||||||
import pwd
|
|
||||||
import jinja2
|
|
||||||
import random
|
|
||||||
import os
|
|
||||||
import string
|
|
||||||
|
|
||||||
def randomString(stringLength=16):
|
|
||||||
letters = string.ascii_lowercase
|
|
||||||
return ''.join(random.choice(letters) for i in range(stringLength))
|
|
||||||
|
|
||||||
def read_conf(f):
|
|
||||||
ret = {}
|
|
||||||
f = open(f, "r")
|
|
||||||
lines = f.readlines()
|
|
||||||
for line in lines:
|
|
||||||
line = line.strip()
|
|
||||||
eline = line.split(' ')
|
|
||||||
if len(eline) >= 2:
|
|
||||||
ret[eline[0]] = eline[1]
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
print("Usage: python setup.py [options]\n\n\
|
|
||||||
options:\n\
|
|
||||||
-h : show usage.\n\
|
|
||||||
-d domain : your domain - mydomain.tld.\n\
|
|
||||||
[-u uuid] : the uuid of the user. Optional.\n\
|
|
||||||
[-p path] : the path of the websocket. Optional.\n\
|
|
||||||
[-s subdomain] : your subdomain. Optional.\n\
|
|
||||||
[-e email] : your email. Optional.\n\
|
|
||||||
[-c conf] : load config from file. Optional.\n\n")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
email = None
|
|
||||||
subdomain = None
|
|
||||||
domain = None
|
|
||||||
conf_file = None
|
|
||||||
uid = os.getuid()
|
|
||||||
gid = os.getgid()
|
|
||||||
v_uuid = None
|
|
||||||
v_path = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
opts , _ = getopt.getopt(sys.argv[1:], "hd:s:e:c:u:p:")
|
|
||||||
except getopt.GetoptError as err:
|
|
||||||
print(str(err))
|
|
||||||
usage()
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
for o, a in opts:
|
|
||||||
if o == "-h":
|
|
||||||
usage()
|
|
||||||
sys.exit(0)
|
|
||||||
elif o == "-d":
|
|
||||||
if domain != None:
|
|
||||||
print("Can specify maximum ONE domain.")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
domain = a
|
|
||||||
elif o == "-s":
|
|
||||||
if subdomain != None:
|
|
||||||
print("Can specify maximum ONE subdomain.")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
subdomain = a
|
|
||||||
elif o == "-e":
|
|
||||||
if email != None:
|
|
||||||
print("Can specify maximum ONE email.")
|
|
||||||
else:
|
|
||||||
email = a
|
|
||||||
elif o == "-c":
|
|
||||||
conf_file = a
|
|
||||||
elif o == "-u":
|
|
||||||
v_uuid = a
|
|
||||||
elif o == "-s":
|
|
||||||
v_path = a
|
|
||||||
|
|
||||||
# overwrite stuff with conf file
|
|
||||||
conf = read_conf(conf_file)
|
|
||||||
|
|
||||||
if "d" in conf:
|
|
||||||
domain = conf["d"]
|
|
||||||
if "s" in conf:
|
|
||||||
subdomain = conf["s"]
|
|
||||||
if "e" in conf:
|
|
||||||
email = conf["e"]
|
|
||||||
if "u" in conf:
|
|
||||||
v_uuid = conf["u"]
|
|
||||||
if "p" in conf:
|
|
||||||
v_path = conf["p"]
|
|
||||||
|
|
||||||
# generate settings if not specified
|
|
||||||
if v_uuid == None:
|
|
||||||
v_uuid = uuid.uuid4()
|
|
||||||
|
|
||||||
if v_path == None:
|
|
||||||
v_path = randomString()
|
|
||||||
|
|
||||||
if domain == None:
|
|
||||||
print("Must specify a domain.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
server_name = None
|
|
||||||
if subdomain == None:
|
|
||||||
server_name = domain
|
|
||||||
else:
|
|
||||||
server_name = subdomain + "." + domain
|
|
||||||
|
|
||||||
# process docker-compose
|
|
||||||
with open("docker-compose.yml", "r") as file:
|
|
||||||
template = jinja2.Template(file.read())
|
|
||||||
|
|
||||||
output = template.render(uid = uid, gid = gid, domain = domain, \
|
|
||||||
subdomain = (subdomain if subdomain != None else ""), \
|
|
||||||
only_sub = ("true" if subdomain != None else "false"), \
|
|
||||||
email = ("dummy@dummy.com" if email == None else email))
|
|
||||||
|
|
||||||
with open("docker-compose.yml", "w") as file:
|
|
||||||
file.write(output)
|
|
||||||
|
|
||||||
# process v2ray/config
|
|
||||||
with open("v2ray/config.json", "r") as file:
|
|
||||||
template = jinja2.Template(file.read())
|
|
||||||
|
|
||||||
output = template.render(uuid = v_uuid, path = v_path)
|
|
||||||
|
|
||||||
with open("v2ray/config.json", "w") as file:
|
|
||||||
file.write(output)
|
|
||||||
|
|
||||||
# process nginx/nginx/site-confs/default
|
|
||||||
with open("nginx/nginx/site-confs/default", "r") as file:
|
|
||||||
template = jinja2.Template(file.read())
|
|
||||||
|
|
||||||
output = template.render(server_name = server_name, path = v_path)
|
|
||||||
|
|
||||||
with open("nginx/nginx/site-confs/default", "w") as file:
|
|
||||||
file.write(output)
|
|
||||||
|
|
||||||
# process client.json
|
|
||||||
with open("client.json", "r") as file:
|
|
||||||
template = jinja2.Template(file.read())
|
|
||||||
|
|
||||||
output = template.render(uuid = v_uuid, path = v_path, server_name = server_name)
|
|
||||||
|
|
||||||
with open("client.json", "w") as file:
|
|
||||||
file.write(output)
|
|
||||||
|
|
||||||
print("Processed all files. The detailed client config is written to client.conf.\n" + \
|
|
||||||
" Summary:\n" + \
|
|
||||||
" Server Address: " + server_name + "\n" \
|
|
||||||
" Path: " + v_path + "\n" \
|
|
||||||
" UUID: " + str(v_uuid) + "\n" \
|
|
||||||
"Please run docker-compose up -d to start the service.")
|
|
||||||
|
|
||||||
main()
|
|
8
watchtower.in
Normal file
8
watchtower.in
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
watchtower:
|
||||||
|
container_name: v2ray_watchtower
|
||||||
|
image: containrrr/watchtower
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- br-v2ray
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
Loading…
Reference in New Issue
Block a user