diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/dockerimage.yml
new file mode 100644
index 0000000..f4961b4
--- /dev/null
+++ b/.github/workflows/dockerimage.yml
@@ -0,0 +1,38 @@
+name: V2ray Heroku Docker Image
+
+on:
+ push:
+ schedule:
+ - cron: "0 0 * * 5"
+
+jobs:
+
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Build the Docker image
+ run: docker build . --file Dockerfile --tag v2heroku:$GITHUB_SHA
+
+ run:
+
+ needs: build
+ runs-on: ubuntu-latest
+
+ env:
+ AppName: test
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Prepare environment
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install unzip python3 python3-pip -y
+ sudo pip3 install requests
+
+ - name: Run the program
+ run: |
+ cd ./worker
+ sudo -E python3 ./deploy.py
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index c48cfd6..4c1002a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,12 @@
-FROM debian:sid
+FROM python:3.7-stretch
-RUN apt update -y \
- && apt upgrade -y \
- && apt install -y wget unzip qrencode
+RUN apt-get update -y \
+ && apt-get install -y unzip \
+ && python3 -V \
+ && pip3 install requests -U
-ADD entrypoint.sh /entrypoint.sh
-RUN chmod +x /entrypoint.sh
-CMD /entrypoint.sh
+ADD worker /worker
+
+CMD cd /worker \
+ && python3 ./deploy.py \
+ && bash ./run.sh
\ No newline at end of file
diff --git a/README.md b/README.md
index 78adc4f..ba6a5fc 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,32 @@
-# 一键部署 v2ray 到 heroku
-[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy)
-- - -
-- - -
-1.部署时配置 v2ray core 的版本、Vmess协议的UUID、AlterId、Path和连接缓存。
+#
一键部署 v2ray 到 Heroku
+**本程序[以GPL-3.0开源许可开源](https://github.com/mnixry/v2ray-heroku-fix/blob/master/LICENSE#L591),仅供学习交流参考使用,对于使用本程序造成的一切后果作者概不承担!**
-2.如果输入AppName变量,则自动生成订阅地址和二维码,通过配置V2_QR_Path变量修改地址
-二维码地址:https://test.herokuapp.com/1234/v2.png
-订阅地址:https://test.herokuapp.com/1234 (test改成自己的app名称,如果更改了V2_QR_Path,同时也要将对应的1234改成修改后的)
+![](https://github.com/mnixry/v2ray-heroku-fix/workflows/V2ray%20Heroku%20Docker%20Image/badge.svg)
-3.服务端部署后,点 open app ,能正常显示网页,地址补上path后访问显示 Bad Request,表示部署成功。
+---
-4.更新 v2ray 版本,访问 https://dashboard.heroku.com/apps 选择部署好v2ray的app,如果VER变量为 latest。直接选择More --> Restart all dynos, 程序自动重启,可通过view Logs确认进度。(更新指定版本: Settings --> Reveal Config Varsapp -->VER,修改成需要的版本号,例如 3.21)
+## 停止维护
-# 参考
-https://github.com/v2ray/v2ray-core
+**由于Heroku的用户协议禁止作为代理使用,本项目停止更新**
-https://github.com/wangyi2005/v2ray-heroku
+**正在研究采用kubesail提供的服务实现类似功能**
-https://github.com/1715173329/v2ray-heroku-undone
+
+## 部署方法
+1. 点击下方按钮跳转Heroku部署(需要注册账号)
+ - [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://dashboard.heroku.com/new?template=https://github.com/mnixry/v2ray-heroku-fix)
+
+2. 跟着提示走吧(逃
+
+3. 服务端部署后,点 `open app`,能正常显示反代理的网页,地址补上V2ray路径后访问显示`Bad Request`,表示部署成功。
+
+4. 更新 v2ray 版本
+ - 访问 https://dashboard.heroku.com/apps 选择部署好v2ray的app
+ - 直接选择`More` --> `Restart all dynos`
+
+## 参考链接:
+> [V2ray-Core](https://github.com/v2ray/v2ray-core)
+
+> [v2ray-heroku](https://github.com/wangyi2005/v2ray-heroku)
+
+> [v2ray-heroku-undone](https://github.com/1715173329/v2ray-heroku-undone)
diff --git a/app.json b/app.json
index aa7e2c1..3dded51 100644
--- a/app.json
+++ b/app.json
@@ -1,38 +1,40 @@
{
- "name": "V2ray简易部署",
+ "name": "V2ray-Heroku部署",
"description": "Deploy V2ray to Heroku.",
- "keywords": ["V2ray"],
+ "keywords": [
+ "V2ray"
+ ],
"env": {
"AppName": {
- "description": "请输入最上方填写的App Name,用于生成二维码和订阅链接,如果不想生成输入no",
- "value": "no"
- },
- "VER": {
- "description": "默认latest安装最新版本V2Ray (输入V2Ray 版本号 进行指定版本安装。例如:3.22)",
- "value": "latest"
- },
+ "description": "请输入最上方填写的App Name,用于订阅链接,必填!",
+ "value": ""
+ },
+ "Subscribe_Address": {
+ "description": "请输入查看订阅的地址,前面不用加`/`",
+ "value": "subscribe"
+ },
"UUID": {
- "description": "Vmess协议默认UUID,请输入自己的UUID",
- "value": "4890bd47-5180-4b1c-9a5d-3ef686543112"
- },
+ "description": "请输入自己的UUID,如无程序会自动随机一份",
+ "value": "",
+ "required": false
+ },
"AlterID": {
- "description": "AlterID大小,推荐10,数值越大内存占用越高",
- "value": "10"
- },
+ "description": "AlterID大小,推荐16,数值越大内存占用越高",
+ "value": "16",
+ "required": false
+ },
"V2_Path": {
- "description": "Path路径,默认/FreeApp",
- "value": "/FreeApp"
- },
- "V2_QR_Path": {
- "description": "二维码和订阅地址路径,默认1234。如AppName变量为no,此变量没有作用",
- "value": "1234"
- },
- "V2RAY_RAY_BUFFER_SIZE": {
- "description": "每个连接的缓存大小,单位MB,默认10。如果感觉有断流现象,请考虑将缓存改成1",
- "value": "10"
- }
+ "description": "Path路径,默认留空则随机生成一份",
+ "value": "",
+ "required": false
+ },
+ "Anti_Proxy_Path": {
+ "description": "反代理的网站地址,默认为百度",
+ "value": "https://www.baidu.com",
+ "required": true
+ }
},
- "website": "https://github.com/ki8852/v2ray-heroku-undone",
- "repository": "https://github.com/ki8852/v2ray-heroku-undone",
+ "website": "https://github.com/mnixry/v2ray-heroku-fix",
+ "repository": "https://github.com/mnixry/v2ray-heroku-fix",
"stack": "container"
- }
+}
\ No newline at end of file
diff --git a/demo.tar.gz b/demo.tar.gz
deleted file mode 100644
index 42cfb19..0000000
Binary files a/demo.tar.gz and /dev/null differ
diff --git a/entrypoint.sh b/entrypoint.sh
deleted file mode 100644
index 11d33a8..0000000
--- a/entrypoint.sh
+++ /dev/null
@@ -1,129 +0,0 @@
-#! /bin/bash
-if [[ -z "${UUID}" ]]; then
- UUID="4890bd47-5180-4b1c-9a5d-3ef686543112"
-fi
-
-if [[ -z "${AlterID}" ]]; then
- AlterID="10"
-fi
-
-if [[ -z "${V2_Path}" ]]; then
- V2_Path="/FreeApp"
-fi
-
-if [[ -z "${V2_QR_Path}" ]]; then
- V2_QR_Code="1234"
-fi
-
-rm -rf /etc/localtime
-ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
-date -R
-
-SYS_Bit="$(getconf LONG_BIT)"
-[[ "$SYS_Bit" == '32' ]] && BitVer='_linux_386.tar.gz'
-[[ "$SYS_Bit" == '64' ]] && BitVer='_linux_amd64.tar.gz'
-
-if [ "$VER" = "latest" ]; then
- V_VER=`wget -qO- "https://api.github.com/repos/v2ray/v2ray-core/releases/latest" | grep 'tag_name' | cut -d\" -f4`
-else
- V_VER="v$VER"
-fi
-
-mkdir /v2raybin
-cd /v2raybin
-wget --no-check-certificate -qO 'v2ray.zip' "https://github.com/v2ray/v2ray-core/releases/download/$V_VER/v2ray-linux-$SYS_Bit.zip"
-unzip v2ray.zip
-rm -rf v2ray.zip
-chmod +x /v2raybin/v2ray-$V_VER-linux-$SYS_Bit/*
-
-C_VER=`wget -qO- "https://api.github.com/repos/mholt/caddy/releases/latest" | grep 'tag_name' | cut -d\" -f4`
-mkdir /caddybin
-cd /caddybin
-wget --no-check-certificate -qO 'caddy.tar.gz' "https://github.com/mholt/caddy/releases/download/$C_VER/caddy_$C_VER$BitVer"
-tar xvf caddy.tar.gz
-rm -rf caddy.tar.gz
-chmod +x caddy
-cd /root
-mkdir /wwwroot
-cd /wwwroot
-
-wget --no-check-certificate -qO 'demo.tar.gz' "https://github.com/ki8852/v2ray-heroku-undone/raw/master/demo.tar.gz"
-tar xvf demo.tar.gz
-rm -rf demo.tar.gz
-
-cat <<-EOF > /v2raybin/v2ray-$V_VER-linux-$SYS_Bit/config.json
-{
- "log":{
- "loglevel":"warning"
- },
- "inbound":{
- "protocol":"vmess",
- "listen":"127.0.0.1",
- "port":2333,
- "settings":{
- "clients":[
- {
- "id":"${UUID}",
- "level":1,
- "alterId":${AlterID}
- }
- ]
- },
- "streamSettings":{
- "network":"ws",
- "wsSettings":{
- "path":"${V2_Path}"
- }
- }
- },
- "outbound":{
- "protocol":"freedom",
- "settings":{
- }
- }
-}
-EOF
-
-cat <<-EOF > /caddybin/Caddyfile
-http://0.0.0.0:${PORT}
-{
- root /wwwroot
- index index.html
- timeouts none
- proxy ${V2_Path} localhost:2333 {
- websocket
- header_upstream -Origin
- }
-}
-EOF
-
-cat <<-EOF > /v2raybin/vmess.json
-{
- "v": "2",
- "ps": "${AppName}.herokuapp.com",
- "add": "${AppName}.herokuapp.com",
- "port": "443",
- "id": "${UUID}",
- "aid": "${AlterID}",
- "net": "ws",
- "type": "none",
- "host": "",
- "path": "${V2_Path}",
- "tls": "tls"
-}
-EOF
-
-if [ "$AppName" = "no" ]; then
- echo "不生成二维码"
-else
- mkdir /wwwroot/$V2_QR_Path
- vmess="vmess://$(cat /v2raybin/vmess.json | base64 -w 0)"
- Linkbase64=$(echo -n "${vmess}" | tr -d '\n' | base64 -w 0)
- echo "${Linkbase64}" | tr -d '\n' > /wwwroot/$V2_QR_Path/index.html
- echo -n "${vmess}" | qrencode -s 6 -o /wwwroot/$V2_QR_Path/v2.png
-fi
-
-cd /v2raybin/v2ray-$V_VER-linux-$SYS_Bit
-./v2ray &
-cd /caddybin
-./caddy -conf="Caddyfile"
diff --git a/worker/deploy.py b/worker/deploy.py
new file mode 100644
index 0000000..b115d9f
--- /dev/null
+++ b/worker/deploy.py
@@ -0,0 +1,181 @@
+import json
+import os
+import platform
+import subprocess
+from base64 import urlsafe_b64encode
+from logging import basicConfig, getLogger
+from random import randint
+from secrets import token_urlsafe
+from shutil import rmtree
+from uuid import uuid4
+
+import requests
+
+assert os.getenv('AppName')
+
+basicConfig(level=20)
+
+def GetEnv(key:str,default=None):
+ envGet = os.getenv(key)
+ if not envGet:
+ return default
+ else:
+ return envGet
+
+LOGGER = getLogger('worker')
+LOGGER_CONFIG = LOGGER.getChild('config')
+LOGGER_COMMAND = LOGGER.getChild('command')
+WORK_DIR = os.path.abspath(os.getcwd())
+SETTINGS: dict = {
+ 'name': GetEnv('AppName'),
+ 'subscribe_path': GetEnv('Subscribe_Address', token_urlsafe(16)),
+ 'uuid': GetEnv('UUID', str(uuid4())),
+ 'port': randint(1000, 60000),
+ 'alter_id': GetEnv('AlterID', 16),
+ 'v2ray_path': GetEnv('V2_Path', f'/{token_urlsafe(8)}'),
+ 'reverse_proxy': GetEnv('Anti_Proxy_Path', 'https://www.baidu.com')
+}
+
+
+def execute(command: str, block: bool = True) -> int:
+ LOGGER_COMMAND.info(f'Execute command "{command}"')
+ if block:
+ return subprocess.run(command, shell=True, check=True).returncode
+ else:
+ return subprocess.Popen(command, shell=True).returncode
+
+
+def mkdir(dir: str):
+ if os.path.exists(dir):
+ rmtree(dir)
+ os.mkdir(dir)
+
+
+LOGGER_CONFIG.info('Start setting the system time zone')
+execute(r"""rm -rf /etc/localtime \
+ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
+ && date -R""")
+
+LOGGER_CONFIG.info(
+ f'The platform information is as follows: {platform.uname()}')
+if platform.architecture()[0] == '32bit':
+ SYS_BIT = 32
+elif platform.architecture()[0] == '64bit':
+ SYS_BIT = 64
+else:
+ raise RuntimeError(
+ f'Unrecognized operating platform: {platform.architecture()}')
+
+LOGGER_CONFIG.info('Start getting V2ray version list')
+RELEASE_INFO = requests.get(
+ 'https://api.github.com/repos/v2ray/v2ray-core/releases/latest').json()
+for perAsset in RELEASE_INFO['assets']:
+ LOGGER_CONFIG.debug(f'Check asset {perAsset["name"]}')
+ if perAsset['name'] == f'v2ray-linux-{SYS_BIT}.zip':
+ DOWNLOAD_LINK = perAsset['browser_download_url']
+ break
+else:
+ raise FileNotFoundError('No suitable version found')
+
+LOGGER_CONFIG.info('Start downloading V2ray core files')
+LOGGER_CONFIG.debug(f'Download link: {DOWNLOAD_LINK}')
+with open(os.path.join(WORK_DIR, 'v2ray.zip'), 'wb') as f:
+ f.write(requests.get(DOWNLOAD_LINK).content)
+
+LOGGER_CONFIG.info('Start downloading Caddy files')
+CADDY_URL = 'https://github.com/caddyserver/caddy/releases/download/v1.0.4/caddy_v1.0.4_linux_amd64.tar.gz' if (
+ SYS_BIT == 64
+) else 'https://github.com/caddyserver/caddy/releases/download/v1.0.4/caddy_v1.0.4_linux_386.tar.gz'
+LOGGER_CONFIG.debug(f'Download link: {CADDY_URL}')
+with open(os.path.join(WORK_DIR, 'caddy.tar.gz'), 'wb') as f:
+ f.write(requests.get(CADDY_URL).content)
+
+LOGGER_CONFIG.info('Extract the downloaded file')
+mkdir('v2ray')
+execute(
+ f'unzip "{os.path.join(WORK_DIR,"v2ray.zip")}" -d "{os.path.join(WORK_DIR,"v2ray")}"'
+)
+mkdir('caddy')
+execute(
+ f'tar -xvf "{os.path.join(WORK_DIR,"caddy.tar.gz")}" -C "{os.path.join(WORK_DIR,"caddy")}"'
+)
+
+LOGGER_CONFIG.info('Start writing configuration files')
+V2_CONF = {
+ "log": {
+ "loglevel": "warning"
+ },
+ "inbound": {
+ "protocol": "vmess",
+ "listen": "127.0.0.1",
+ "port": SETTINGS['port'],
+ "settings": {
+ "clients": [{
+ "id": SETTINGS['uuid'],
+ "level": 1,
+ "alterId": int(SETTINGS['alter_id'])
+ }]
+ },
+ "streamSettings": {
+ "network": "ws",
+ "wsSettings": {
+ "path": SETTINGS['v2ray_path']
+ }
+ }
+ },
+ "outbound": {
+ "protocol": "freedom",
+ "settings": {}
+ }
+}
+with open(os.path.join(WORK_DIR, './v2ray/config.json'),
+ 'wt',
+ encoding='utf-8') as f:
+ f.write(json.dumps(V2_CONF, indent=4, sort_keys=True))
+
+SHARE_CONF = {
+ "v": "2",
+ "ps": f"{SETTINGS['name']}.herokuapp.com",
+ "add": f"{SETTINGS['name']}.herokuapp.com",
+ "port": "443",
+ "id": SETTINGS['uuid'],
+ "aid": SETTINGS['alter_id'],
+ "net": "ws",
+ "type": "none",
+ "host": f"{SETTINGS['name']}.herokuapp.com",
+ "path": SETTINGS['v2ray_path'],
+ "tls": "tls"
+}
+
+V2_LINK = urlsafe_b64encode(json.dumps(SHARE_CONF).encode()).decode()
+mkdir('subscribe')
+with open(os.path.join(WORK_DIR, 'subscribe', 'index.html'),
+ 'wt',
+ encoding='utf-8') as f:
+ f.write(f'vmess://{V2_LINK}')
+
+CADDY_CONF = f""":{GetEnv('PORT',80)} {{
+ gzip
+ log stdout
+ timeouts none
+
+ proxy / {SETTINGS['reverse_proxy']} {{
+ except /{SETTINGS['subscribe_path']}
+ }}
+
+ proxy {SETTINGS['v2ray_path']} 127.0.0.1:{SETTINGS['port']} {{
+ websocket
+ header_upstream -Origin
+ }}
+
+}}
+:{GetEnv('PORT',80)}/{SETTINGS['subscribe_path']} {{
+ gzip
+ log stdout
+ root "{os.path.join(WORK_DIR,'subscribe')}"
+}}"""
+with open(os.path.join(WORK_DIR, './caddy/Caddyfile'), 'wt',
+ encoding='utf-8') as f:
+ f.write(CADDY_CONF)
+
+LOGGER_CONFIG.info(f'The V2ray link is vmess://{V2_LINK}')
\ No newline at end of file
diff --git a/worker/run.sh b/worker/run.sh
new file mode 100644
index 0000000..09b9b77
--- /dev/null
+++ b/worker/run.sh
@@ -0,0 +1,9 @@
+cd /worker
+chmod -R +x /worker
+echo "v2ray config:"
+cat ./v2ray/config.json
+echo "caddy config:"
+cat ./caddy/Caddyfile
+
+./v2ray/v2ray &
+./caddy/caddy -conf ./caddy/Caddyfile
\ No newline at end of file