├── .github └── workflows │ └── release.yml ├── LICENSE ├── README.md ├── install.sh ├── src ├── bbr.sh ├── caddy.sh ├── core.sh ├── dns.sh ├── download.sh ├── help.sh ├── init.sh └── systemd.sh └── xray.sh /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: push 4 | 5 | permissions: 6 | contents: write 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: checkout 13 | uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 0 16 | - name: get ver 17 | run: | 18 | echo "$(cat xray.sh | grep ver=)" >> $GITHUB_ENV 19 | echo "old=$(git tag | tail -n1)" >> $GITHUB_ENV 20 | # - name: test 21 | # if: env.is_sh_ver == env.old 22 | # run: | 23 | # echo not found new version. 24 | # exit 1 25 | - name: zip 26 | run: zip -9vr code.zip . -x .\* 27 | - name: release 28 | uses: softprops/action-gh-release@v1 29 | with: 30 | files: code.zip 31 | tag_name: ${{ env.is_sh_ver }} 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | 最好用的 Xray 一键安装脚本 & 管理脚本 4 | 5 | # 特点 6 | 7 | - 快速安装 8 | - 无敌好用 9 | - 零学习成本 10 | - 自动化 TLS 11 | - 简化所有流程 12 | - 屏蔽 BT 13 | - 屏蔽中国 IP 14 | - 使用 API 操作 15 | - 兼容 Xray 命令 16 | - 强大的快捷参数 17 | - 支持所有常用协议 18 | - 一键添加 VLESS-REALITY (默认) 19 | - 一键添加 Shadowsocks 2022 20 | - 一键添加 VMess-(TCP/mKCP) 21 | - 一键添加 VMess-(WS/gRPC)-TLS 22 | - 一键添加 VLESS-(WS/gRPC/XHTTP)-TLS 23 | - 一键添加 Trojan-(WS/gRPC)-TLS 24 | - 一键添加 VMess-(TCP/mKCP) 动态端口 25 | - 一键启用 BBR 26 | - 一键更改伪装网站 27 | - 一键更改 (端口/UUID/密码/域名/路径/加密方式/SNI/动态端口/等...) 28 | - 还有更多... 29 | 30 | # 设计理念 31 | 32 | 设计理念为:**高效率,超快速,极易用** 33 | 34 | 脚本基于作者的自身使用需求,以 **多配置同时运行** 为核心设计 35 | 36 | 并且专门优化了,添加、更改、查看、删除、这四项常用功能 37 | 38 | 你只需要一条命令即可完成 添加、更改、查看、删除、等操作 39 | 40 | 例如,添加一个配置仅需不到 1 秒!瞬间完成添加!其他操作亦是如此! 41 | 42 | 脚本的参数非常高效率并且超级易用,请掌握参数的使用 43 | 44 | # 文档 45 | 46 | 安装及使用:https://233boy.com/xray/xray-script/ 47 | 48 | # 帮助 49 | 50 | 使用:`xray help` 51 | 52 | ``` 53 | Xray script v1.21 by 233boy 54 | Usage: xray [options]... [args]... 55 | 56 | 基本: 57 | v, version 显示当前版本 58 | ip 返回当前主机的 IP 59 | pbk 同等于 xray x25519 60 | get-port 返回一个可用的端口 61 | ss2022 返回一个可用于 Shadowsocks 2022 的密码 62 | 63 | 一般: 64 | a, add [protocol] [args... | auto] 添加配置 65 | c, change [name] [option] [args... | auto] 更改配置 66 | d, del [name] 删除配置** 67 | i, info [name] 查看配置 68 | qr [name] 二维码信息 69 | url [name] URL 信息 70 | log 查看日志 71 | logerr 查看错误日志 72 | 73 | 更改: 74 | dp, dynamicport [name] [start | auto] [end] 更改动态端口 75 | full [name] [...] 更改多个参数 76 | id [name] [uuid | auto] 更改 UUID 77 | host [name] [domain] 更改域名 78 | port [name] [port | auto] 更改端口 79 | path [name] [path | auto] 更改路径 80 | passwd [name] [password | auto] 更改密码 81 | key [name] [Private key | atuo] [Public key] 更改密钥 82 | type [name] [type | auto] 更改伪装类型 83 | method [name] [method | auto] 更改加密方式 84 | sni [name] [ ip | domain] 更改 serverName 85 | seed [name] [seed | auto] 更改 mKCP seed 86 | new [name] [...] 更改协议 87 | web [name] [domain] 更改伪装网站 88 | 89 | 进阶: 90 | dns [...] 设置 DNS 91 | dd, ddel [name...] 删除多个配置** 92 | fix [name] 修复一个配置 93 | fix-all 修复全部配置 94 | fix-caddyfile 修复 Caddyfile 95 | fix-config.json 修复 config.json 96 | 97 | 管理: 98 | un, uninstall 卸载 99 | u, update [core | sh | dat | caddy] [ver] 更新 100 | U, update.sh 更新脚本 101 | s, status 运行状态 102 | start, stop, restart [caddy] 启动, 停止, 重启 103 | t, test 测试运行 104 | reinstall 重装脚本 105 | 106 | 测试: 107 | client [name] 显示用于客户端 JSON, 仅供参考 108 | debug [name] 显示一些 debug 信息, 仅供参考 109 | gen [...] 同等于 add, 但只显示 JSON 内容, 不创建文件, 测试使用 110 | genc [name] 显示用于客户端部分 JSON, 仅供参考 111 | no-auto-tls [...] 同等于 add, 但禁止自动配置 TLS, 可用于 *TLS 相关协议 112 | xapi [...] 同等于 xray api, 但 API 后端使用当前运行的 Xray 服务 113 | 114 | 其他: 115 | bbr 启用 BBR, 如果支持 116 | bin [...] 运行 Xray 命令, 例如: xray bin help 117 | api, x25519, tls, run, uuid [...] 兼容 Xray 命令 118 | h, help 显示此帮助界面 119 | 120 | 谨慎使用 del, ddel, 此选项会直接删除配置; 无需确认 121 | 反馈问题) https://github.com/233boy/xray/issues 122 | 文档(doc) https://233boy.com/xray/xray-script/ 123 | ``` -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | author=233boy 4 | # github=https://github.com/233boy/xray 5 | 6 | # bash fonts colors 7 | red='\e[31m' 8 | yellow='\e[33m' 9 | gray='\e[90m' 10 | green='\e[92m' 11 | blue='\e[94m' 12 | magenta='\e[95m' 13 | cyan='\e[96m' 14 | none='\e[0m' 15 | _red() { echo -e ${red}$@${none}; } 16 | _blue() { echo -e ${blue}$@${none}; } 17 | _cyan() { echo -e ${cyan}$@${none}; } 18 | _green() { echo -e ${green}$@${none}; } 19 | _yellow() { echo -e ${yellow}$@${none}; } 20 | _magenta() { echo -e ${magenta}$@${none}; } 21 | _red_bg() { echo -e "\e[41m$@${none}"; } 22 | 23 | is_err=$(_red_bg 错误!) 24 | is_warn=$(_red_bg 警告!) 25 | 26 | err() { 27 | echo -e "\n$is_err $@\n" && exit 1 28 | } 29 | 30 | warn() { 31 | echo -e "\n$is_warn $@\n" 32 | } 33 | 34 | # root 35 | [[ $EUID != 0 ]] && err "当前非 ${yellow}ROOT用户.${none}" 36 | 37 | # yum or apt-get, ubuntu/debian/centos 38 | cmd=$(type -P apt-get || type -P yum) 39 | [[ ! $cmd ]] && err "此脚本仅支持 ${yellow}(Ubuntu or Debian or CentOS)${none}." 40 | 41 | # systemd 42 | [[ ! $(type -P systemctl) ]] && { 43 | err "此系统缺少 ${yellow}(systemctl)${none}, 请尝试执行:${yellow} ${cmd} update -y;${cmd} install systemd -y ${none}来修复此错误." 44 | } 45 | 46 | # wget installed or none 47 | is_wget=$(type -P wget) 48 | 49 | # x64 50 | case $(uname -m) in 51 | amd64 | x86_64) 52 | is_jq_arch=amd64 53 | is_core_arch="64" 54 | ;; 55 | *aarch64* | *armv8*) 56 | is_jq_arch=arm64 57 | is_core_arch="arm64-v8a" 58 | ;; 59 | *) 60 | err "此脚本仅支持 64 位系统..." 61 | ;; 62 | esac 63 | 64 | is_core=xray 65 | is_core_name=Xray 66 | is_core_dir=/etc/$is_core 67 | is_core_bin=$is_core_dir/bin/$is_core 68 | is_core_repo=xtls/$is_core-core 69 | is_conf_dir=$is_core_dir/conf 70 | is_log_dir=/var/log/$is_core 71 | is_sh_bin=/usr/local/bin/$is_core 72 | is_sh_dir=$is_core_dir/sh 73 | is_sh_repo=$author/$is_core 74 | is_pkg="wget unzip" 75 | is_config_json=$is_core_dir/config.json 76 | tmp_var_lists=( 77 | tmpcore 78 | tmpsh 79 | tmpjq 80 | is_core_ok 81 | is_sh_ok 82 | is_jq_ok 83 | is_pkg_ok 84 | ) 85 | 86 | # tmp dir 87 | tmpdir=$(mktemp -u) 88 | [[ ! $tmpdir ]] && { 89 | tmpdir=/tmp/tmp-$RANDOM 90 | } 91 | 92 | # set up var 93 | for i in ${tmp_var_lists[*]}; do 94 | export $i=$tmpdir/$i 95 | done 96 | 97 | # load bash script. 98 | load() { 99 | . $is_sh_dir/src/$1 100 | } 101 | 102 | # wget add --no-check-certificate 103 | _wget() { 104 | [[ $proxy ]] && export https_proxy=$proxy 105 | wget --no-check-certificate $* 106 | } 107 | 108 | # print a mesage 109 | msg() { 110 | case $1 in 111 | warn) 112 | local color=$yellow 113 | ;; 114 | err) 115 | local color=$red 116 | ;; 117 | ok) 118 | local color=$green 119 | ;; 120 | esac 121 | 122 | echo -e "${color}$(date +'%T')${none}) ${2}" 123 | } 124 | 125 | # show help msg 126 | show_help() { 127 | echo -e "Usage: $0 [-f xxx | -l | -p xxx | -v xxx | -h]" 128 | echo -e " -f, --core-file 自定义 $is_core_name 文件路径, e.g., -f /root/${is_core}-linux-64.zip" 129 | echo -e " -l, --local-install 本地获取安装脚本, 使用当前目录" 130 | echo -e " -p, --proxy 使用代理下载, e.g., -p http://127.0.0.1:2333" 131 | echo -e " -v, --core-version 自定义 $is_core_name 版本, e.g., -v v1.8.1" 132 | echo -e " -h, --help 显示此帮助界面\n" 133 | 134 | exit 0 135 | } 136 | 137 | # install dependent pkg 138 | install_pkg() { 139 | cmd_not_found= 140 | for i in $*; do 141 | [[ ! $(type -P $i) ]] && cmd_not_found="$cmd_not_found,$i" 142 | done 143 | if [[ $cmd_not_found ]]; then 144 | pkg=$(echo $cmd_not_found | sed 's/,/ /g') 145 | msg warn "安装依赖包 >${pkg}" 146 | $cmd install -y $pkg &>/dev/null 147 | if [[ $? != 0 ]]; then 148 | [[ $cmd =~ yum ]] && yum install epel-release -y &>/dev/null 149 | $cmd update -y &>/dev/null 150 | $cmd install -y $pkg &>/dev/null 151 | [[ $? == 0 ]] && >$is_pkg_ok 152 | else 153 | >$is_pkg_ok 154 | fi 155 | else 156 | >$is_pkg_ok 157 | fi 158 | } 159 | 160 | # download file 161 | download() { 162 | case $1 in 163 | core) 164 | link=https://github.com/${is_core_repo}/releases/latest/download/${is_core}-linux-${is_core_arch}.zip 165 | [[ $is_core_ver ]] && link="https://github.com/${is_core_repo}/releases/download/${is_core_ver}/${is_core}-linux-${is_core_arch}.zip" 166 | name=$is_core_name 167 | tmpfile=$tmpcore 168 | is_ok=$is_core_ok 169 | ;; 170 | sh) 171 | link=https://github.com/${is_sh_repo}/releases/latest/download/code.zip 172 | name="$is_core_name 脚本" 173 | tmpfile=$tmpsh 174 | is_ok=$is_sh_ok 175 | ;; 176 | jq) 177 | link=https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-$is_jq_arch 178 | name="jq" 179 | tmpfile=$tmpjq 180 | is_ok=$is_jq_ok 181 | ;; 182 | esac 183 | 184 | msg warn "下载 ${name} > ${link}" 185 | if _wget -t 3 -q -c $link -O $tmpfile; then 186 | mv -f $tmpfile $is_ok 187 | fi 188 | } 189 | 190 | # get server ip 191 | get_ip() { 192 | export "$(_wget -4 -qO- https://one.one.one.one/cdn-cgi/trace | grep ip=)" &>/dev/null 193 | [[ -z $ip ]] && export "$(_wget -6 -qO- https://one.one.one.one/cdn-cgi/trace | grep ip=)" &>/dev/null 194 | } 195 | 196 | # check background tasks status 197 | check_status() { 198 | # dependent pkg install fail 199 | [[ ! -f $is_pkg_ok ]] && { 200 | msg err "安装依赖包失败" 201 | msg err "请尝试手动安装依赖包: $cmd update -y; $cmd install -y $pkg" 202 | is_fail=1 203 | } 204 | 205 | # download file status 206 | if [[ $is_wget ]]; then 207 | [[ ! -f $is_core_ok ]] && { 208 | msg err "下载 ${is_core_name} 失败" 209 | is_fail=1 210 | } 211 | [[ ! -f $is_sh_ok ]] && { 212 | msg err "下载 ${is_core_name} 脚本失败" 213 | is_fail=1 214 | } 215 | [[ ! -f $is_jq_ok ]] && { 216 | msg err "下载 jq 失败" 217 | is_fail=1 218 | } 219 | else 220 | [[ ! $is_fail ]] && { 221 | is_wget=1 222 | [[ ! $is_core_file ]] && download core & 223 | [[ ! $local_install ]] && download sh & 224 | [[ $jq_not_found ]] && download jq & 225 | get_ip 226 | wait 227 | check_status 228 | } 229 | fi 230 | 231 | # found fail status, remove tmp dir and exit. 232 | [[ $is_fail ]] && { 233 | exit_and_del_tmpdir 234 | } 235 | } 236 | 237 | # parameters check 238 | pass_args() { 239 | while [[ $# -gt 0 ]]; do 240 | case $1 in 241 | -f | --core-file) 242 | [[ -z $2 ]] && { 243 | err "($1) 缺少必需参数, 正确使用示例: [$1 /root/$is_core-linux-64.zip]" 244 | } || [[ ! -f $2 ]] && { 245 | err "($2) 不是一个常规的文件." 246 | } 247 | is_core_file=$2 248 | shift 2 249 | ;; 250 | -l | --local-install) 251 | [[ ! -f ${PWD}/src/core.sh || ! -f ${PWD}/$is_core.sh ]] && { 252 | err "当前目录 (${PWD}) 非完整的脚本目录." 253 | } 254 | local_install=1 255 | shift 1 256 | ;; 257 | -p | --proxy) 258 | [[ -z $2 ]] && { 259 | err "($1) 缺少必需参数, 正确使用示例: [$1 http://127.0.0.1:2333 or -p socks5://127.0.0.1:2333]" 260 | } 261 | proxy=$2 262 | shift 2 263 | ;; 264 | -v | --core-version) 265 | [[ -z $2 ]] && { 266 | err "($1) 缺少必需参数, 正确使用示例: [$1 v1.8.1]" 267 | } 268 | is_core_ver=v${2#v} 269 | shift 2 270 | ;; 271 | -h | --help) 272 | show_help 273 | ;; 274 | *) 275 | echo -e "\n${is_err} ($@) 为未知参数...\n" 276 | show_help 277 | ;; 278 | esac 279 | done 280 | [[ $is_core_ver && $is_core_file ]] && { 281 | err "无法同时自定义 ${is_core_name} 版本和 ${is_core_name} 文件." 282 | } 283 | } 284 | 285 | # exit and remove tmpdir 286 | exit_and_del_tmpdir() { 287 | rm -rf $tmpdir 288 | [[ ! $1 ]] && { 289 | msg err "哦豁.." 290 | msg err "安装过程出现错误..." 291 | echo -e "反馈问题) https://github.com/${is_sh_repo}/issues" 292 | echo 293 | exit 1 294 | } 295 | exit 296 | } 297 | 298 | # main 299 | main() { 300 | 301 | # check old version 302 | [[ -f $is_sh_bin && -d $is_core_dir/bin && -d $is_sh_dir && -d $is_conf_dir ]] && { 303 | err "检测到脚本已安装, 如需重装请使用${green} ${is_core} reinstall ${none}命令." 304 | } 305 | 306 | # check parameters 307 | [[ $# -gt 0 ]] && pass_args $@ 308 | 309 | # show welcome msg 310 | clear 311 | echo 312 | echo "........... $is_core_name script by $author .........." 313 | echo 314 | 315 | # start installing... 316 | msg warn "开始安装..." 317 | [[ $is_core_ver ]] && msg warn "${is_core_name} 版本: ${yellow}$is_core_ver${none}" 318 | [[ $proxy ]] && msg warn "使用代理: ${yellow}$proxy${none}" 319 | # create tmpdir 320 | mkdir -p $tmpdir 321 | # if is_core_file, copy file 322 | [[ $is_core_file ]] && { 323 | cp -f $is_core_file $is_core_ok 324 | msg warn "${yellow}${is_core_name} 文件使用 > $is_core_file${none}" 325 | } 326 | # local dir install sh script 327 | [[ $local_install ]] && { 328 | >$is_sh_ok 329 | msg warn "${yellow}本地获取安装脚本 > $PWD ${none}" 330 | } 331 | 332 | timedatectl set-ntp true &>/dev/null 333 | [[ $? != 0 ]] && { 334 | msg warn "${yellow}\e[4m提醒!!! 无法设置自动同步时间, 可能会影响使用 VMess 协议.${none}" 335 | } 336 | 337 | # install dependent pkg 338 | install_pkg $is_pkg & 339 | 340 | # jq 341 | if [[ $(type -P jq) ]]; then 342 | >$is_jq_ok 343 | else 344 | jq_not_found=1 345 | fi 346 | # if wget installed. download core, sh, jq, get ip 347 | [[ $is_wget ]] && { 348 | [[ ! $is_core_file ]] && download core & 349 | [[ ! $local_install ]] && download sh & 350 | [[ $jq_not_found ]] && download jq & 351 | get_ip 352 | } 353 | 354 | # waiting for background tasks is done 355 | wait 356 | 357 | # check background tasks status 358 | check_status 359 | 360 | # test $is_core_file 361 | if [[ $is_core_file ]]; then 362 | unzip -qo $is_core_ok -d $tmpdir/testzip &>/dev/null 363 | [[ $? != 0 ]] && { 364 | msg err "${is_core_name} 文件无法通过测试." 365 | exit_and_del_tmpdir 366 | } 367 | for i in ${is_core} geoip.dat geosite.dat; do 368 | [[ ! -f $tmpdir/testzip/$i ]] && is_file_err=1 && break 369 | done 370 | [[ $is_file_err ]] && { 371 | msg err "${is_core_name} 文件无法通过测试." 372 | exit_and_del_tmpdir 373 | } 374 | fi 375 | 376 | # get server ip. 377 | [[ ! $ip ]] && { 378 | msg err "获取服务器 IP 失败." 379 | exit_and_del_tmpdir 380 | } 381 | 382 | # create sh dir... 383 | mkdir -p $is_sh_dir 384 | 385 | # copy sh file or unzip sh zip file. 386 | if [[ $local_install ]]; then 387 | cp -rf $PWD/* $is_sh_dir 388 | else 389 | unzip -qo $is_sh_ok -d $is_sh_dir 390 | fi 391 | 392 | # create core bin dir 393 | mkdir -p $is_core_dir/bin 394 | # copy core file or unzip core zip file 395 | if [[ $is_core_file ]]; then 396 | cp -rf $tmpdir/testzip/* $is_core_dir/bin 397 | else 398 | unzip -qo $is_core_ok -d $is_core_dir/bin 399 | fi 400 | 401 | # add alias 402 | echo "alias $is_core=$is_sh_bin" >>/root/.bashrc 403 | 404 | # core command 405 | ln -sf $is_sh_dir/$is_core.sh $is_sh_bin 406 | 407 | # jq 408 | [[ $jq_not_found ]] && mv -f $is_jq_ok /usr/bin/jq 409 | 410 | # chmod 411 | chmod +x $is_core_bin $is_sh_bin /usr/bin/jq 412 | 413 | # create log dir 414 | mkdir -p $is_log_dir 415 | 416 | # show a tips msg 417 | msg ok "生成配置文件..." 418 | 419 | # create systemd service 420 | load systemd.sh 421 | is_new_install=1 422 | install_service $is_core &>/dev/null 423 | 424 | # create condf dir 425 | mkdir -p $is_conf_dir 426 | 427 | load core.sh 428 | # create a tcp config 429 | add reality 430 | # remove tmp dir and exit. 431 | exit_and_del_tmpdir ok 432 | } 433 | 434 | # start. 435 | main $@ 436 | -------------------------------------------------------------------------------- /src/bbr.sh: -------------------------------------------------------------------------------- 1 | _open_bbr() { 2 | sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf 3 | sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf 4 | echo "net.ipv4.tcp_congestion_control = bbr" >>/etc/sysctl.conf 5 | echo "net.core.default_qdisc = fq" >>/etc/sysctl.conf 6 | sysctl -p &>/dev/null 7 | echo 8 | _green "..已经启用 BBR 优化...." 9 | echo 10 | } 11 | 12 | _try_enable_bbr() { 13 | local _test1=$(uname -r | cut -d\. -f1) 14 | local _test2=$(uname -r | cut -d\. -f2) 15 | if [[ $_test1 -eq 4 && $_test2 -ge 9 ]] || [[ $_test1 -ge 5 ]]; then 16 | _open_bbr 17 | else 18 | err "不支持启用 BBR 优化." 19 | fi 20 | } 21 | -------------------------------------------------------------------------------- /src/caddy.sh: -------------------------------------------------------------------------------- 1 | caddy_config() { 2 | is_caddy_site_file=$is_caddy_conf/${host}.conf 3 | case $1 in 4 | new) 5 | mkdir -p $is_caddy_dir $is_caddy_dir/sites $is_caddy_conf 6 | cat >$is_caddyfile <<-EOF 7 | # don't edit this file # 8 | # for more info, see https://233boy.com/$is_core/caddy-auto-tls/ 9 | # 不要编辑这个文件 # 10 | # 更多相关请阅读此文章: https://233boy.com/$is_core/caddy-auto-tls/ 11 | # https://caddyserver.com/docs/caddyfile/options 12 | { 13 | admin off 14 | http_port $is_http_port 15 | https_port $is_https_port 16 | } 17 | import $is_caddy_conf/*.conf 18 | import $is_caddy_dir/sites/*.conf 19 | EOF 20 | ;; 21 | *ws*) 22 | cat >${is_caddy_site_file} <<<" 23 | ${host}:${is_https_port} { 24 | reverse_proxy ${path} 127.0.0.1:${port} 25 | import ${is_caddy_site_file}.add 26 | }" 27 | ;; 28 | *h2*) 29 | cat >${is_caddy_site_file} <<<" 30 | ${host}:${is_https_port} { 31 | reverse_proxy ${path} h2c://127.0.0.1:${port} 32 | import ${is_caddy_site_file}.add 33 | }" 34 | ;; 35 | *grpc*) 36 | cat >${is_caddy_site_file} <<<" 37 | ${host}:${is_https_port} { 38 | reverse_proxy /${path}/* h2c://127.0.0.1:${port} 39 | import ${is_caddy_site_file}.add 40 | }" 41 | ;; 42 | xhttp) 43 | cat >${is_caddy_site_file} <<<" 44 | ${host}:${is_https_port} { 45 | reverse_proxy ${path}/* h2c://127.0.0.1:${port} 46 | import ${is_caddy_site_file}.add 47 | }" 48 | ;; 49 | proxy) 50 | 51 | cat >${is_caddy_site_file}.add <<<" 52 | reverse_proxy https://$proxy_site { 53 | header_up Host {upstream_hostport} 54 | }" 55 | ;; 56 | esac 57 | [[ $1 != "new" && $1 != 'proxy' ]] && { 58 | [[ ! -f ${is_caddy_site_file}.add ]] && echo "# see https://233boy.com/$is_core/caddy-auto-tls/" >${is_caddy_site_file}.add 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/core.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | protocol_list=( 4 | VMess-TCP 5 | VMess-mKCP 6 | # VMess-QUIC 7 | # VMess-H2-TLS 8 | VMess-WS-TLS 9 | VMess-gRPC-TLS 10 | # VLESS-H2-TLS 11 | VLESS-WS-TLS 12 | VLESS-gRPC-TLS 13 | VLESS-XHTTP-TLS 14 | VLESS-REALITY 15 | # Trojan-H2-TLS 16 | Trojan-WS-TLS 17 | Trojan-gRPC-TLS 18 | Shadowsocks 19 | # Dokodemo-Door 20 | VMess-TCP-dynamic-port 21 | VMess-mKCP-dynamic-port 22 | # VMess-QUIC-dynamic-port 23 | Socks 24 | ) 25 | ss_method_list=( 26 | aes-128-gcm 27 | aes-256-gcm 28 | chacha20-ietf-poly1305 29 | xchacha20-ietf-poly1305 30 | 2022-blake3-aes-128-gcm 31 | 2022-blake3-aes-256-gcm 32 | 2022-blake3-chacha20-poly1305 33 | ) 34 | header_type_list=( 35 | none 36 | srtp 37 | utp 38 | wechat-video 39 | dtls 40 | wireguard 41 | ) 42 | mainmenu=( 43 | "添加配置" 44 | "更改配置" 45 | "查看配置" 46 | "删除配置" 47 | "运行管理" 48 | "更新" 49 | "卸载" 50 | "帮助" 51 | "其他" 52 | "关于" 53 | ) 54 | info_list=( 55 | "协议 (protocol)" 56 | "地址 (address)" 57 | "端口 (port)" 58 | "用户ID (id)" 59 | "传输协议 (network)" 60 | "伪装类型 (type)" 61 | "伪装域名 (host)" 62 | "路径 (path)" 63 | "传输层安全 (TLS)" 64 | "mKCP seed" 65 | "密码 (password)" 66 | "加密方式 (encryption)" 67 | "链接 (URL)" 68 | "目标地址 (remote addr)" 69 | "目标端口 (remote port)" 70 | "流控 (flow)" 71 | "SNI (serverName)" 72 | "指纹 (Fingerprint)" 73 | "公钥 (Public key)" 74 | "用户名 (Username)" 75 | ) 76 | change_list=( 77 | "更改协议" 78 | "更改端口" 79 | "更改域名" 80 | "更改路径" 81 | "更改密码" 82 | "更改 UUID" 83 | "更改加密方式" 84 | "更改伪装类型" 85 | "更改目标地址" 86 | "更改目标端口" 87 | "更改密钥" 88 | "更改 SNI (serverName)" 89 | "更改动态端口" 90 | "更改伪装网站" 91 | "更改 mKCP seed" 92 | "更改用户名 (Username)" 93 | ) 94 | servername_list=( 95 | www.amazon.com 96 | www.ebay.com 97 | www.paypal.com 98 | www.cloudflare.com 99 | dash.cloudflare.com 100 | aws.amazon.com 101 | ) 102 | 103 | is_random_ss_method=${ss_method_list[$(shuf -i 4-6 -n1)]} # random only use ss2022 104 | is_random_header_type=${header_type_list[$(shuf -i 1-5 -n1)]} # random dont use none 105 | is_random_servername=${servername_list[$(shuf -i 0-${#servername_list[@]} -n1) - 1]} 106 | 107 | msg() { 108 | echo -e "$@" 109 | } 110 | 111 | msg_ul() { 112 | echo -e "\e[4m$@\e[0m" 113 | } 114 | 115 | # pause 116 | pause() { 117 | echo 118 | echo -ne "按 $(_green Enter 回车键) 继续, 或按 $(_red Ctrl + C) 取消." 119 | read -rs -d $'\n' 120 | echo 121 | } 122 | 123 | get_uuid() { 124 | tmp_uuid=$(cat /proc/sys/kernel/random/uuid) 125 | } 126 | 127 | get_ip() { 128 | [[ $ip || $is_no_auto_tls || $is_gen || $is_dont_get_ip ]] && return 129 | export "$(_wget -4 -qO- https://one.one.one.one/cdn-cgi/trace | grep ip=)" &>/dev/null 130 | [[ ! $ip ]] && export "$(_wget -6 -qO- https://one.one.one.one/cdn-cgi/trace | grep ip=)" &>/dev/null 131 | [[ ! $ip ]] && { 132 | err "获取服务器 IP 失败.." 133 | } 134 | } 135 | 136 | get_port() { 137 | is_count=0 138 | while :; do 139 | ((is_count++)) 140 | if [[ $is_count -ge 233 ]]; then 141 | err "自动获取可用端口失败次数达到 233 次, 请检查端口占用情况." 142 | fi 143 | tmp_port=$(shuf -i 445-65535 -n 1) 144 | [[ ! $(is_test port_used $tmp_port) && $tmp_port != $port ]] && break 145 | done 146 | } 147 | 148 | get_pbk() { 149 | is_tmp_pbk=($($is_core_bin x25519 | sed 's/.*://')) 150 | is_private_key=${is_tmp_pbk[0]} 151 | is_public_key=${is_tmp_pbk[1]} 152 | } 153 | 154 | show_list() { 155 | PS3='' 156 | COLUMNS=1 157 | select i in "$@"; do echo; done & 158 | wait 159 | # i=0 160 | # for v in "$@"; do 161 | # ((i++)) 162 | # echo "$i) $v" 163 | # done 164 | # echo 165 | 166 | } 167 | 168 | is_test() { 169 | case $1 in 170 | number) 171 | echo $2 | egrep '^[1-9][0-9]?+$' 172 | ;; 173 | port) 174 | if [[ $(is_test number $2) ]]; then 175 | [[ $2 -le 65535 ]] && echo ok 176 | fi 177 | ;; 178 | port_used) 179 | [[ $(is_port_used $2) && ! $is_cant_test_port ]] && echo ok 180 | ;; 181 | domain) 182 | echo $2 | egrep -i '^\w(\w|\-|\.)?+\.\w+$' 183 | ;; 184 | path) 185 | echo $2 | egrep -i '^\/\w(\w|\-|\/)?+\w$' 186 | ;; 187 | uuid) 188 | echo $2 | egrep -i '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' 189 | ;; 190 | esac 191 | 192 | } 193 | 194 | is_port_used() { 195 | if [[ $(type -P netstat) ]]; then 196 | [[ ! $is_used_port ]] && is_used_port="$(netstat -tunlp | sed -n 's/.*:\([0-9]\+\).*/\1/p' | sort -nu)" 197 | echo $is_used_port | sed 's/ /\n/g' | grep ^${1}$ 198 | return 199 | fi 200 | if [[ $(type -P ss) ]]; then 201 | [[ ! $is_used_port ]] && is_used_port="$(ss -tunlp | sed -n 's/.*:\([0-9]\+\).*/\1/p' | sort -nu)" 202 | echo $is_used_port | sed 's/ /\n/g' | grep ^${1}$ 203 | return 204 | fi 205 | is_cant_test_port=1 206 | msg "$is_warn 无法检测端口是否可用." 207 | msg "请执行: $(_yellow "${cmd} update -y; ${cmd} install net-tools -y") 来修复此问题." 208 | } 209 | 210 | # ask input a string or pick a option for list. 211 | ask() { 212 | case $1 in 213 | set_ss_method) 214 | is_tmp_list=(${ss_method_list[@]}) 215 | is_default_arg=$is_random_ss_method 216 | is_opt_msg="\n请选择加密方式:\n" 217 | is_opt_input_msg="(默认\e[92m $is_default_arg\e[0m):" 218 | is_ask_set=ss_method 219 | ;; 220 | set_header_type) 221 | is_tmp_list=(${header_type_list[@]}) 222 | is_default_arg=$is_random_header_type 223 | [[ $(grep -i tcp <<<"$is_new_protocol-$net") ]] && { 224 | is_tmp_list=(none http) 225 | is_default_arg=none 226 | } 227 | is_opt_msg="\n请选择伪装类型:\n" 228 | is_opt_input_msg="(默认\e[92m $is_default_arg\e[0m):" 229 | is_ask_set=header_type 230 | [[ $is_use_header_type ]] && return 231 | ;; 232 | set_protocol) 233 | is_tmp_list=(${protocol_list[@]}) 234 | [[ $is_no_auto_tls ]] && { 235 | unset is_tmp_list 236 | for v in ${protocol_list[@]}; do 237 | [[ $(grep -i tls$ <<<$v) ]] && is_tmp_list=(${is_tmp_list[@]} $v) 238 | done 239 | } 240 | is_opt_msg="\n请选择协议:\n" 241 | is_ask_set=is_new_protocol 242 | ;; 243 | set_change_list) 244 | is_tmp_list=() 245 | for v in ${is_can_change[@]}; do 246 | is_tmp_list+=("${change_list[$v]}") 247 | done 248 | is_opt_msg="\n请选择更改:\n" 249 | is_ask_set=is_change_str 250 | is_opt_input_msg=$3 251 | ;; 252 | string) 253 | is_ask_set=$2 254 | is_opt_input_msg=$3 255 | ;; 256 | list) 257 | is_ask_set=$2 258 | [[ ! $is_tmp_list ]] && is_tmp_list=($3) 259 | is_opt_msg=$4 260 | is_opt_input_msg=$5 261 | ;; 262 | get_config_file) 263 | is_tmp_list=("${is_all_json[@]}") 264 | is_opt_msg="\n请选择配置:\n" 265 | is_ask_set=is_config_file 266 | ;; 267 | mainmenu) 268 | is_tmp_list=("${mainmenu[@]}") 269 | is_ask_set=is_main_pick 270 | is_emtpy_exit=1 271 | ;; 272 | esac 273 | msg $is_opt_msg 274 | [[ ! $is_opt_input_msg ]] && is_opt_input_msg="请选择 [\e[91m1-${#is_tmp_list[@]}\e[0m]:" 275 | [[ $is_tmp_list ]] && show_list "${is_tmp_list[@]}" 276 | while :; do 277 | echo -ne $is_opt_input_msg 278 | read REPLY 279 | [[ ! $REPLY && $is_emtpy_exit ]] && exit 280 | [[ ! $REPLY && $is_default_arg ]] && export $is_ask_set=$is_default_arg && break 281 | [[ "$REPLY" == "${is_str}2${is_get}3${is_opt}3" && $is_ask_set == 'is_main_pick' ]] && { 282 | msg "\n${is_get}2${is_str}3${is_msg}3b${is_tmp}o${is_opt}y\n" && exit 283 | } 284 | if [[ ! $is_tmp_list ]]; then 285 | [[ $(grep port <<<$is_ask_set) ]] && { 286 | [[ ! $(is_test port "$REPLY") ]] && { 287 | msg "$is_err 请输入正确的端口, 可选(1-65535)" 288 | continue 289 | } 290 | if [[ $(is_test port_used $REPLY) && $is_ask_set != 'door_port' ]]; then 291 | msg "$is_err 无法使用 ($REPLY) 端口." 292 | continue 293 | fi 294 | } 295 | [[ $(grep path <<<$is_ask_set) && ! $(is_test path "$REPLY") ]] && { 296 | [[ ! $tmp_uuid ]] && get_uuid 297 | msg "$is_err 请输入正确的路径, 例如: /$tmp_uuid" 298 | continue 299 | } 300 | [[ $(grep uuid <<<$is_ask_set) && ! $(is_test uuid "$REPLY") ]] && { 301 | [[ ! $tmp_uuid ]] && get_uuid 302 | msg "$is_err 请输入正确的 UUID, 例如: $tmp_uuid" 303 | continue 304 | } 305 | [[ $(grep ^y$ <<<$is_ask_set) ]] && { 306 | [[ $(grep -i ^y$ <<<"$REPLY") ]] && break 307 | msg "请输入 (y)" 308 | continue 309 | } 310 | [[ $REPLY ]] && export $is_ask_set=$REPLY && msg "使用: ${!is_ask_set}" && break 311 | else 312 | [[ $(is_test number "$REPLY") ]] && is_ask_result=${is_tmp_list[$REPLY - 1]} 313 | [[ $is_ask_result ]] && export $is_ask_set="$is_ask_result" && msg "选择: ${!is_ask_set}" && break 314 | fi 315 | 316 | msg "输入${is_err}" 317 | done 318 | unset is_opt_msg is_opt_input_msg is_tmp_list is_ask_result is_default_arg is_emtpy_exit 319 | } 320 | 321 | # create file 322 | create() { 323 | case $1 in 324 | server) 325 | get new 326 | 327 | # file name 328 | if [[ $host ]]; then 329 | is_config_name=$2-${host}.json 330 | else 331 | is_config_name=$2-${port}.json 332 | fi 333 | is_json_file=$is_conf_dir/$is_config_name 334 | # get json 335 | [[ $is_change || ! $json_str ]] && get protocol $2 336 | is_listen='listen:"0.0.0.0"' 337 | [[ $host ]] && is_listen=${is_listen/0.0.0.0/127.0.0.1} 338 | is_sniffing='sniffing:{enabled:true,destOverride:["http","tls"]}' 339 | is_new_json=$(jq '{inbounds:[{tag:"'$is_config_name'",port:'"$port"','"$is_listen"',protocol:"'$is_protocol'",'"$json_str"','"$is_sniffing"'}]}' <<<{}) 340 | if [[ $is_dynamic_port ]]; then 341 | [[ ! $is_dynamic_port_range ]] && get dynamic-port 342 | is_new_dynamic_port_json=$(jq '{inbounds:[{tag:"'$is_config_name-link.json'",port:"'$is_dynamic_port_range'",'"$is_listen"',protocol:"vmess",'"$is_stream"','"$is_sniffing"',allocate:{strategy:"random"}}]}' <<<{}) 343 | fi 344 | [[ $is_test_json ]] && return # tmp test 345 | # only show json, dont save to file. 346 | [[ $is_gen ]] && { 347 | msg 348 | jq <<<$is_new_json 349 | msg 350 | [[ $is_new_dynamic_port_json ]] && jq <<<$is_new_dynamic_port_json && msg 351 | return 352 | } 353 | # del old file 354 | [[ $is_config_file ]] && is_no_del_msg=1 && del $is_config_file 355 | # save json to file 356 | cat <<<$is_new_json >$is_json_file 357 | [[ $is_new_dynamic_port_json ]] && { 358 | is_dynamic_port_link_file=$is_json_file-link.json 359 | cat <<<$is_new_dynamic_port_json >$is_dynamic_port_link_file 360 | } 361 | if [[ $is_new_install ]]; then 362 | # config.json 363 | create config.json 364 | else 365 | # use api add config 366 | api add $is_json_file $is_dynamic_port_link_file &>/dev/null 367 | fi 368 | # caddy auto tls 369 | [[ $is_caddy && $host && ! $is_no_auto_tls ]] && { 370 | create caddy $net 371 | } 372 | # restart core 373 | [[ $is_api_fail ]] && manage restart & 374 | ;; 375 | client) 376 | is_tls=tls 377 | is_client=1 378 | get info $2 379 | [[ ! $is_client_id_json ]] && err "($is_config_name) 不支持生成客户端配置." 380 | [[ $host ]] && is_stream="${is_stream/network:\"$net\"/network:\"$net\",security:\"tls\"}" 381 | is_new_json=$(jq '{outbounds:[{tag:"'$is_config_name'",protocol:"'$is_protocol'",'"$is_client_id_json"','"$is_stream"'}]}' <<<{}) 382 | if [[ $is_full_client ]]; then 383 | is_dns='dns:{servers:[{address:"223.5.5.5",domain:["geosite:cn","geosite:geolocation-cn"],expectIPs:["geoip:cn"]},"1.1.1.1","8.8.8.8"]}' 384 | is_route='routing:{rules:[{type:"field",outboundTag:"direct",ip:["geoip:cn","geoip:private"]},{type:"field",outboundTag:"direct",domain:["geosite:cn","geosite:geolocation-cn"]}]}' 385 | is_inbounds='inbounds:[{port:2333,listen:"127.0.0.1",protocol:"socks",settings:{udp:true},sniffing:{enabled:true,destOverride:["http","tls"]}}]' 386 | is_outbounds='outbounds:[{tag:"'$is_config_name'",protocol:"'$is_protocol'",'"$is_client_id_json"','"$is_stream"'},{tag:"direct",protocol:"freedom"}]' 387 | is_new_json=$(jq '{'$is_dns,$is_route,$is_inbounds,$is_outbounds'}' <<<{}) 388 | fi 389 | msg 390 | jq <<<$is_new_json 391 | msg 392 | ;; 393 | caddy) 394 | load caddy.sh 395 | [[ $is_install_caddy ]] && caddy_config new 396 | [[ ! $(grep "$is_caddy_conf" $is_caddyfile) ]] && { 397 | msg "import $is_caddy_conf/*.conf" >>$is_caddyfile 398 | } 399 | [[ ! -d $is_caddy_conf ]] && mkdir -p $is_caddy_conf 400 | caddy_config $2 401 | manage restart caddy & 402 | ;; 403 | config.json) 404 | get_port 405 | is_log='log:{access:"/var/log/'"$is_core"'/access.log",error:"/var/log/'"$is_core"'/error.log",loglevel:"warning"}' 406 | is_dns='dns:{}' 407 | is_api='api:{tag:"api",services:["HandlerService","LoggerService","StatsService"]}' 408 | is_stats='stats:{}' 409 | is_policy_system='system:{statsInboundUplink:true,statsInboundDownlink:true,statsOutboundUplink:true,statsOutboundDownlink:true}' 410 | is_policy='policy:{levels:{"0":{handshake:'"$((${tmp_port:0:1} + 1))"',connIdle:'"${tmp_port:0:3}"',uplinkOnly:'"$((${tmp_port:2:1} + 1))"',downlinkOnly:'"$((${tmp_port:3:1} + 3))"',statsUserUplink:true,statsUserDownlink:true}},'"$is_policy_system"'}' 411 | is_ban_ad='{type:"field",domain:["geosite:category-ads-all"],marktag:"ban_ad",outboundTag:"block"}' 412 | is_ban_bt='{type:"field",protocol:["bittorrent"],marktag:"ban_bt",outboundTag:"block"}' 413 | is_ban_cn='{type:"field",ip:["geoip:cn"],marktag:"ban_geoip_cn",outboundTag:"block"}' 414 | is_openai='{type:"field",domain:["geosite:openai"],marktag:"fix_openai",outboundTag:"direct"}' 415 | is_routing='routing:{domainStrategy:"IPIfNonMatch",rules:[{type:"field",inboundTag:["api"],outboundTag:"api"},'"$is_ban_bt"','"$is_ban_cn"','"$is_openai"',{type:"field",ip:["geoip:private"],outboundTag:"block"}]}' 416 | is_inbounds='inbounds:[{tag:"api",port:'"$tmp_port"',listen:"127.0.0.1",protocol:"dokodemo-door",settings:{address:"127.0.0.1"}}]' 417 | is_outbounds='outbounds:[{tag:"direct",protocol:"freedom"},{tag:"block",protocol:"blackhole"}]' 418 | is_server_config_json=$(jq '{'"$is_log"','"$is_dns"','"$is_api"','"$is_stats"','"$is_policy"','"$is_routing"','"$is_inbounds"','"$is_outbounds"'}' <<<{}) 419 | cat <<<$is_server_config_json >$is_config_json 420 | manage restart & 421 | ;; 422 | esac 423 | } 424 | 425 | # change config file 426 | change() { 427 | is_change=1 428 | is_dont_show_info=1 429 | if [[ $2 ]]; then 430 | case ${2,,} in 431 | full) 432 | is_change_id=full 433 | ;; 434 | new) 435 | is_change_id=0 436 | ;; 437 | port) 438 | is_change_id=1 439 | ;; 440 | host) 441 | is_change_id=2 442 | ;; 443 | path) 444 | is_change_id=3 445 | ;; 446 | pass | passwd | password) 447 | is_change_id=4 448 | ;; 449 | id | uuid) 450 | is_change_id=5 451 | ;; 452 | ssm | method | ss-method | ss_method) 453 | is_change_id=6 454 | ;; 455 | type | header | header-type | header_type) 456 | is_change_id=7 457 | ;; 458 | dda | door-addr | door_addr) 459 | is_change_id=8 460 | ;; 461 | ddp | door-port | door_port) 462 | is_change_id=9 463 | ;; 464 | key | publickey | privatekey) 465 | is_change_id=10 466 | ;; 467 | sni | servername | servernames) 468 | is_change_id=11 469 | ;; 470 | dp | dyp | dynamic | dynamicport | dynamic-port) 471 | is_change_id=12 472 | ;; 473 | web | proxy-site) 474 | is_change_id=13 475 | ;; 476 | seed | kcpseed | kcp-seed | kcp_seed) 477 | is_change_id=14 478 | ;; 479 | *) 480 | [[ $is_try_change ]] && return 481 | err "无法识别 ($2) 更改类型." 482 | ;; 483 | esac 484 | fi 485 | [[ $is_try_change ]] && return 486 | [[ $is_dont_auto_exit ]] && { 487 | get info $1 488 | } || { 489 | [[ $is_change_id ]] && { 490 | is_change_msg=${change_list[$is_change_id]} 491 | [[ $is_change_id == 'full' ]] && { 492 | [[ $3 ]] && is_change_msg="更改多个参数" || is_change_msg= 493 | } 494 | [[ $is_change_msg ]] && _green "\n快速执行: $is_change_msg" 495 | } 496 | info $1 497 | [[ $is_auto_get_config ]] && msg "\n自动选择: $is_config_file" 498 | } 499 | is_old_net=$net 500 | [[ $host ]] && net=$is_protocol-$net-tls 501 | [[ $is_reality ]] && net=reality 502 | [[ $is_dynamic_port ]] && net=${net}d 503 | [[ $3 == 'auto' ]] && is_auto=1 504 | # if is_dont_show_info exist, cant show info. 505 | is_dont_show_info= 506 | # if not prefer args, show change list and then get change id. 507 | [[ ! $is_change_id ]] && { 508 | ask set_change_list 509 | is_change_id=${is_can_change[$REPLY - 1]} 510 | } 511 | case $is_change_id in 512 | full) 513 | add $net ${@:3} 514 | ;; 515 | 0) 516 | # new protocol 517 | is_set_new_protocol=1 518 | add ${@:3} 519 | ;; 520 | 1) 521 | # new port 522 | is_new_port=$3 523 | [[ $host && ! $is_caddy ]] && err "($is_config_file) 不支持更改端口, 因为没啥意义." 524 | if [[ $is_new_port && ! $is_auto ]]; then 525 | [[ ! $(is_test port $is_new_port) ]] && err "请输入正确的端口, 可选(1-65535)" 526 | [[ $is_new_port != 443 && $(is_test port_used $is_new_port) ]] && err "无法使用 ($is_new_port) 端口" 527 | fi 528 | [[ $is_auto ]] && get_port && is_new_port=$tmp_port 529 | [[ ! $is_new_port ]] && ask string is_new_port "请输入新端口:" 530 | if [[ $is_caddy && $host ]]; then 531 | net=$is_old_net 532 | is_https_port=$is_new_port 533 | load caddy.sh 534 | caddy_config $net 535 | manage restart caddy & 536 | info 537 | else 538 | add $net $is_new_port 539 | fi 540 | ;; 541 | 2) 542 | # new host 543 | is_new_host=$3 544 | [[ ! $host ]] && err "($is_config_file) 不支持更改域名." 545 | [[ ! $is_new_host ]] && ask string is_new_host "请输入新域名:" 546 | old_host=$host # del old host 547 | add $net $is_new_host 548 | ;; 549 | 3) 550 | # new path 551 | is_new_path=$3 552 | [[ ! $path ]] && err "($is_config_file) 不支持更改路径." 553 | [[ $is_auto ]] && get_uuid && is_new_path=/$tmp_uuid 554 | [[ ! $is_new_path ]] && ask string is_new_path "请输入新路径:" 555 | add $net auto auto $is_new_path 556 | ;; 557 | 4) 558 | # new password 559 | is_new_pass=$3 560 | if [[ $net == 'ss' || $is_trojan || $is_socks_pass ]]; then 561 | [[ $is_auto ]] && get_uuid && is_new_pass=$tmp_uuid 562 | else 563 | err "($is_config_file) 不支持更改密码." 564 | fi 565 | [[ ! $is_new_pass ]] && ask string is_new_pass "请输入新密码:" 566 | trojan_password=$is_new_pass 567 | ss_password=$is_new_pass 568 | is_socks_pass=$is_new_pass 569 | add $net 570 | ;; 571 | 5) 572 | # new uuid 573 | is_new_uuid=$3 574 | [[ ! $uuid ]] && err "($is_config_file) 不支持更改 UUID." 575 | [[ $is_auto ]] && get_uuid && is_new_uuid=$tmp_uuid 576 | [[ ! $is_new_uuid ]] && ask string is_new_uuid "请输入新 UUID:" 577 | add $net auto $is_new_uuid 578 | ;; 579 | 6) 580 | # new method 581 | is_new_method=$3 582 | [[ $net != 'ss' ]] && err "($is_config_file) 不支持更改加密方式." 583 | [[ $is_auto ]] && is_new_method=$is_random_ss_method 584 | [[ ! $is_new_method ]] && { 585 | ask set_ss_method 586 | is_new_method=$ss_method 587 | } 588 | add $net auto auto $is_new_method 589 | ;; 590 | 7) 591 | # new header type 592 | is_new_header_type=$3 593 | [[ ! $header_type ]] && err "($is_config_file) 不支持更改伪装类型." 594 | [[ $is_auto ]] && { 595 | is_new_header_type=$is_random_header_type 596 | if [[ $net == 'tcp' ]]; then 597 | is_tmp_header_type=(none http) 598 | is_new_header_type=${is_tmp_header_type[$(shuf -i 0-1 -n1)]} 599 | fi 600 | } 601 | [[ ! $is_new_header_type ]] && { 602 | ask set_header_type 603 | is_new_header_type=$header_type 604 | } 605 | add $net auto auto $is_new_header_type 606 | ;; 607 | 8) 608 | # new remote addr 609 | is_new_door_addr=$3 610 | [[ $net != 'door' ]] && err "($is_config_file) 不支持更改目标地址." 611 | [[ ! $is_new_door_addr ]] && ask string is_new_door_addr "请输入新的目标地址:" 612 | door_addr=$is_new_door_addr 613 | add $net 614 | ;; 615 | 9) 616 | # new remote port 617 | is_new_door_port=$3 618 | [[ $net != 'door' ]] && err "($is_config_file) 不支持更改目标端口." 619 | [[ ! $is_new_door_port ]] && { 620 | ask string door_port "请输入新的目标端口:" 621 | is_new_door_port=$door_port 622 | } 623 | add $net auto auto $is_new_door_port 624 | ;; 625 | 10) 626 | # new is_private_key is_public_key 627 | is_new_private_key=$3 628 | is_new_public_key=$4 629 | [[ ! $is_reality ]] && err "($is_config_file) 不支持更改密钥." 630 | if [[ $is_auto ]]; then 631 | get_pbk 632 | add $net 633 | else 634 | [[ $is_new_private_key && ! $is_new_public_key ]] && { 635 | err "无法找到 Public key." 636 | } 637 | [[ ! $is_new_private_key ]] && ask string is_new_private_key "请输入新 Private key:" 638 | [[ ! $is_new_public_key ]] && ask string is_new_public_key "请输入新 Public key:" 639 | if [[ $is_new_private_key == $is_new_public_key ]]; then 640 | err "Private key 和 Public key 不能一样." 641 | fi 642 | is_private_key=$is_new_private_key 643 | is_test_json=1 644 | # create server $is_protocol-$net | $is_core_bin -test &>/dev/null 645 | create server $is_protocol-$net 646 | $is_core_bin -test <<<"$is_new_json" &>/dev/null 647 | if [[ $? != 0 ]]; then 648 | err "Private key 无法通过测试." 649 | fi 650 | is_private_key=$is_new_public_key 651 | # create server $is_protocol-$net | $is_core_bin -test &>/dev/null 652 | create server $is_protocol-$net 653 | $is_core_bin -test <<<"$is_new_json" &>/dev/null 654 | if [[ $? != 0 ]]; then 655 | err "Public key 无法通过测试." 656 | fi 657 | is_private_key=$is_new_private_key 658 | is_public_key=$is_new_public_key 659 | is_test_json= 660 | add $net 661 | fi 662 | ;; 663 | 11) 664 | # new serverName 665 | is_new_servername=$3 666 | [[ ! $is_reality ]] && err "($is_config_file) 不支持更改 serverName." 667 | [[ $is_auto ]] && is_new_servername=$is_random_servername 668 | [[ ! $is_new_servername ]] && ask string is_new_servername "请输入新的 serverName:" 669 | is_servername=$is_new_servername 670 | [[ $(grep -i "^233boy.com$" <<<$is_servername) ]] && { 671 | err "你干嘛~哎呦~" 672 | } 673 | add $net 674 | ;; 675 | 12) 676 | # new dynamic-port 677 | is_new_dynamic_port_start=$3 678 | is_new_dynamic_port_end=$4 679 | [[ ! $is_dynamic_port ]] && err "($is_config_file) 不支持更改动态端口." 680 | if [[ $is_auto ]]; then 681 | get dynamic-port 682 | add $net 683 | else 684 | [[ $is_new_dynamic_port_start && ! $is_new_dynamic_port_end ]] && { 685 | err "无法找到动态结束端口." 686 | } 687 | [[ ! $is_new_dynamic_port_start ]] && ask string is_new_dynamic_port_start "请输入新的动态开始端口:" 688 | [[ ! $is_new_dynamic_port_end ]] && ask string is_new_dynamic_port_end "请输入新的动态结束端口:" 689 | add $net auto auto auto $is_new_dynamic_port_start $is_new_dynamic_port_end 690 | fi 691 | ;; 692 | 13) 693 | # new proxy site 694 | is_new_proxy_site=$3 695 | [[ ! $is_caddy && ! $host ]] && { 696 | err "($is_config_file) 不支持更改伪装网站." 697 | } 698 | [[ ! -f $is_caddy_conf/${host}.conf.add ]] && err "无法配置伪装网站." 699 | [[ ! $is_new_proxy_site ]] && ask string is_new_proxy_site "请输入新的伪装网站 (例如 example.com):" 700 | proxy_site=$(sed 's#^.*//##;s#/$##' <<<$is_new_proxy_site) 701 | [[ $(grep -i "^233boy.com$" <<<$proxy_site) ]] && { 702 | err "你干嘛~哎呦~" 703 | } || { 704 | load caddy.sh 705 | caddy_config proxy 706 | manage restart caddy & 707 | } 708 | msg "\n已更新伪装网站为: $(_green $proxy_site) \n" 709 | ;; 710 | 14) 711 | # new kcp seed 712 | is_new_kcp_seed=$3 713 | [[ ! $kcp_seed ]] && err "($is_config_file) 不支持更改 mKCP seed." 714 | [[ $is_auto ]] && get_uuid && is_new_kcp_seed=$tmp_uuid 715 | [[ ! $is_new_kcp_seed ]] && ask string is_new_kcp_seed "请输入新 mKCP seed:" 716 | kcp_seed=$is_new_kcp_seed 717 | add $net 718 | ;; 719 | 15) 720 | # new socks user 721 | [[ ! $is_socks_user ]] && err "($is_config_file) 不支持更改用户名 (Username)." 722 | ask string is_socks_user "请输入新用户名 (Username):" 723 | add $net 724 | ;; 725 | esac 726 | } 727 | 728 | # delete config. 729 | del() { 730 | # dont get ip 731 | is_dont_get_ip=1 732 | [[ $is_conf_dir_empty ]] && return # not found any json file. 733 | # get a config file 734 | [[ ! $is_config_file ]] && get info $1 735 | if [[ $is_config_file ]]; then 736 | if [[ $is_main_start && ! $is_no_del_msg ]]; then 737 | msg "\n是否删除配置文件?: $is_config_file" 738 | pause 739 | fi 740 | api del $is_conf_dir/"$is_config_file" $is_dynamic_port_file &>/dev/null 741 | rm -rf $is_conf_dir/"$is_config_file" $is_dynamic_port_file 742 | [[ $is_api_fail && ! $is_new_json ]] && manage restart & 743 | [[ ! $is_no_del_msg ]] && _green "\n已删除: $is_config_file\n" 744 | 745 | [[ $is_caddy ]] && { 746 | is_del_host=$host 747 | [[ $is_change ]] && { 748 | [[ ! $old_host ]] && return # no host exist or not set new host; 749 | is_del_host=$old_host 750 | } 751 | [[ $is_del_host && $host != $old_host ]] && { 752 | rm -rf $is_caddy_conf/$is_del_host.conf $is_caddy_conf/$is_del_host.conf.add 753 | [[ ! $is_new_json ]] && manage restart caddy & 754 | } 755 | } 756 | fi 757 | if [[ ! $(ls $is_conf_dir | grep .json) && ! $is_change ]]; then 758 | warn "当前配置目录为空! 因为你刚刚删除了最后一个配置文件." 759 | is_conf_dir_empty=1 760 | fi 761 | unset is_dont_get_ip 762 | [[ $is_dont_auto_exit ]] && unset is_config_file 763 | } 764 | 765 | # uninstall 766 | uninstall() { 767 | if [[ $is_caddy ]]; then 768 | is_tmp_list=("卸载 $is_core_name" "卸载 ${is_core_name} & Caddy") 769 | ask list is_do_uninstall 770 | else 771 | ask string y "是否卸载 ${is_core_name}? [y]:" 772 | fi 773 | manage stop &>/dev/null 774 | manage disable &>/dev/null 775 | rm -rf $is_core_dir $is_log_dir $is_sh_bin /lib/systemd/system/$is_core.service 776 | sed -i "/alias $is_core=/d" /root/.bashrc 777 | # uninstall caddy; 2 is ask result 778 | if [[ $REPLY == '2' ]]; then 779 | manage stop caddy &>/dev/null 780 | manage disable caddy &>/dev/null 781 | rm -rf $is_caddy_dir $is_caddy_bin /lib/systemd/system/caddy.service 782 | fi 783 | [[ $is_install_sh ]] && return # reinstall 784 | _green "\n卸载完成!" 785 | msg "脚本哪里需要完善? 请反馈" 786 | msg "反馈问题) $(msg_ul https://github.com/${is_sh_repo}/issues)\n" 787 | } 788 | 789 | # manage run status 790 | manage() { 791 | [[ $is_dont_auto_exit ]] && return 792 | case $1 in 793 | 1 | start) 794 | is_do=start 795 | is_do_msg=启动 796 | is_test_run=1 797 | ;; 798 | 2 | stop) 799 | is_do=stop 800 | is_do_msg=停止 801 | ;; 802 | 3 | r | restart) 803 | is_do=restart 804 | is_do_msg=重启 805 | is_test_run=1 806 | ;; 807 | *) 808 | is_do=$1 809 | is_do_msg=$1 810 | ;; 811 | esac 812 | case $2 in 813 | caddy) 814 | is_do_name=$2 815 | is_run_bin=$is_caddy_bin 816 | is_do_name_msg=Caddy 817 | ;; 818 | *) 819 | is_do_name=$is_core 820 | is_run_bin=$is_core_bin 821 | is_do_name_msg=$is_core_name 822 | ;; 823 | esac 824 | systemctl $is_do $is_do_name 825 | [[ $is_test_run && ! $is_new_install ]] && { 826 | sleep 2 827 | if [[ ! $(pgrep -f $is_run_bin) ]]; then 828 | is_run_fail=${is_do_name_msg,,} 829 | [[ ! $is_no_manage_msg ]] && { 830 | msg 831 | warn "($is_do_msg) $is_do_name_msg 失败" 832 | _yellow "检测到运行失败, 自动执行测试运行." 833 | get test-run 834 | _yellow "测试结束, 请按 Enter 退出." 835 | } 836 | fi 837 | } 838 | } 839 | 840 | # use api add or del inbounds 841 | api() { 842 | [[ ! $1 ]] && err "无法识别 API 的参数." 843 | [[ $is_core_stop ]] && { 844 | warn "$is_core_name 当前处于停止状态." 845 | is_api_fail=1 846 | return 847 | } 848 | case $1 in 849 | add) 850 | is_api_do=adi 851 | ;; 852 | del) 853 | is_api_do=rmi 854 | ;; 855 | s) 856 | is_api_do=stats 857 | ;; 858 | t | sq) 859 | is_api_do=statsquery 860 | ;; 861 | esac 862 | [[ ! $is_api_do ]] && is_api_do=$1 863 | [[ ! $is_api_port ]] && { 864 | is_api_port=$(jq '.inbounds[] | select(.tag == "api") | .port' $is_config_json) 865 | [[ $? != 0 ]] && { 866 | warn "读取 API 端口失败, 无法使用 API 操作." 867 | return 868 | } 869 | } 870 | $is_core_bin api $is_api_do --server=127.0.0.1:$is_api_port ${@:2} 871 | [[ $? != 0 ]] && { 872 | is_api_fail=1 873 | } 874 | } 875 | 876 | # add a config 877 | add() { 878 | is_lower=${1,,} 879 | if [[ $is_lower ]]; then 880 | case $is_lower in 881 | # tcp | kcp | quic | tcpd | kcpd | quicd) 882 | tcp | kcp | tcpd | kcpd) 883 | is_new_protocol=VMess-$(sed 's/^K/mK/;s/D$/-dynamic-port/' <<<${is_lower^^}) 884 | ;; 885 | # ws | h2 | grpc | vws | vh2 | vgrpc | tws | th2 | tgrpc) 886 | ws | grpc | vws | vgrpc | tws | tgrpc) 887 | is_new_protocol=$(sed -E "s/^V/VLESS-/;s/^T/Trojan-/;/^(W|H|G)/{s/^/VMess-/};s/G/g/" <<<${is_lower^^})-TLS 888 | ;; 889 | xhttp) 890 | is_new_protocol=VLESS-XHTTP-TLS 891 | ;; 892 | r | reality) 893 | is_new_protocol=VLESS-REALITY 894 | ;; 895 | ss) 896 | is_new_protocol=Shadowsocks 897 | ;; 898 | door) 899 | is_new_protocol=Dokodemo-Door 900 | ;; 901 | socks) 902 | is_new_protocol=Socks 903 | ;; 904 | # http) 905 | # is_new_protocol=local-$is_lower 906 | # ;; 907 | *) 908 | for v in ${protocol_list[@]}; do 909 | [[ $(egrep -i "^$is_lower$" <<<$v) ]] && is_new_protocol=$v && break 910 | done 911 | 912 | [[ ! $is_new_protocol ]] && err "无法识别 ($1), 请使用: $is_core add [protocol] [args... | auto]" 913 | ;; 914 | esac 915 | fi 916 | 917 | # no prefer protocol 918 | [[ ! $is_new_protocol ]] && ask set_protocol 919 | 920 | case ${is_new_protocol,,} in 921 | *-tls) 922 | is_use_tls=1 923 | is_use_host=$2 924 | is_use_uuid=$3 925 | is_use_path=$4 926 | is_add_opts="[host] [uuid] [/path]" 927 | ;; 928 | vmess*) 929 | is_use_port=$2 930 | is_use_uuid=$3 931 | is_use_header_type=$4 932 | is_use_dynamic_port_start=$5 933 | is_use_dynamic_port_end=$6 934 | [[ $(grep dynamic-port <<<$is_new_protocol) ]] && is_dynamic_port=1 935 | if [[ $is_dynamic_port ]]; then 936 | is_add_opts="[port] [uuid] [type] [start_port] [end_port]" 937 | else 938 | is_add_opts="[port] [uuid] [type]" 939 | fi 940 | ;; 941 | *reality*) 942 | is_reality=1 943 | is_use_port=$2 944 | is_use_uuid=$3 945 | is_use_servername=$4 946 | is_add_opts="[port] [uuid] [sni]" 947 | ;; 948 | shadowsocks) 949 | is_use_port=$2 950 | is_use_pass=$3 951 | is_use_method=$4 952 | is_add_opts="[port] [password] [method]" 953 | ;; 954 | *door) 955 | is_use_port=$2 956 | is_use_door_addr=$3 957 | is_use_door_port=$4 958 | is_add_opts="[port] [remote_addr] [remote_port]" 959 | ;; 960 | socks) 961 | is_socks=1 962 | is_use_port=$2 963 | is_use_socks_user=$3 964 | is_use_socks_pass=$4 965 | is_add_opts="[port] [username] [password]" 966 | ;; 967 | *http) 968 | is_use_port=$2 969 | is_add_opts="[port]" 970 | ;; 971 | esac 972 | 973 | [[ $1 && ! $is_change ]] && { 974 | msg "\n使用协议: $is_new_protocol" 975 | # err msg tips 976 | is_err_tips="\n\n请使用: $(_green $is_core add $1 $is_add_opts) 来添加 $is_new_protocol 配置" 977 | } 978 | 979 | # remove old protocol args 980 | if [[ $is_set_new_protocol ]]; then 981 | case $is_old_net in 982 | tcp) 983 | unset header_type net 984 | ;; 985 | kcp | quic) 986 | kcp_seed= 987 | [[ $(grep -i tcp <<<$is_new_protocol) ]] && header_type= 988 | ;; 989 | h2 | ws | grpc | xhttp) 990 | old_host=$host 991 | if [[ ! $is_use_tls ]]; then 992 | host= 993 | else 994 | [[ $is_old_net == 'grpc' ]] && { 995 | path=/$path 996 | } 997 | fi 998 | [[ ! $(grep -i trojan <<<$is_new_protocol) ]] && is_trojan= 999 | ;; 1000 | ss) 1001 | [[ $(is_test uuid $ss_password) ]] && uuid=$ss_password 1002 | ;; 1003 | esac 1004 | [[ $is_dynamic_port && ! $(grep dynamic-port <<<$is_new_protocol) ]] && { 1005 | is_dynamic_port= 1006 | } 1007 | 1008 | [[ ! $(is_test uuid $uuid) ]] && uuid= 1009 | [[ ! $(grep -i reality <<<$is_new_protocol) ]] && is_reality= 1010 | fi 1011 | 1012 | # no-auto-tls only use h2,ws,grpc 1013 | if [[ $is_no_auto_tls && ! $is_use_tls ]]; then 1014 | err "$is_new_protocol 不支持手动配置 tls." 1015 | fi 1016 | 1017 | # prefer args. 1018 | if [[ $2 ]]; then 1019 | for v in is_use_port is_use_uuid is_use_header_type is_use_host is_use_path is_use_pass is_use_method is_use_door_addr is_use_door_port is_use_dynamic_port_start is_use_dynamic_port_end; do 1020 | [[ ${!v} == 'auto' ]] && unset $v 1021 | done 1022 | 1023 | if [[ $is_use_port ]]; then 1024 | [[ ! $(is_test port ${is_use_port}) ]] && { 1025 | err "($is_use_port) 不是一个有效的端口. $is_err_tips" 1026 | } 1027 | [[ $(is_test port_used $is_use_port) ]] && { 1028 | err "无法使用 ($is_use_port) 端口. $is_err_tips" 1029 | } 1030 | port=$is_use_port 1031 | fi 1032 | if [[ $is_use_door_port ]]; then 1033 | [[ ! $(is_test port ${is_use_door_port}) ]] && { 1034 | err "(${is_use_door_port}) 不是一个有效的目标端口. $is_err_tips" 1035 | } 1036 | door_port=$is_use_door_port 1037 | fi 1038 | if [[ $is_use_uuid ]]; then 1039 | [[ ! $(is_test uuid $is_use_uuid) ]] && { 1040 | err "($is_use_uuid) 不是一个有效的 UUID. $is_err_tips" 1041 | } 1042 | uuid=$is_use_uuid 1043 | fi 1044 | if [[ $is_use_path ]]; then 1045 | [[ ! $(is_test path $is_use_path) ]] && { 1046 | err "($is_use_path) 不是有效的路径. $is_err_tips" 1047 | } 1048 | path=$is_use_path 1049 | fi 1050 | if [[ $is_use_header_type || $is_use_method ]]; then 1051 | is_tmp_use_name=加密方式 1052 | is_tmp_list=${ss_method_list[@]} 1053 | [[ ! $is_use_method ]] && { 1054 | is_tmp_use_name=伪装类型 1055 | ask set_header_type 1056 | } 1057 | for v in ${is_tmp_list[@]}; do 1058 | [[ $(egrep -i "^${is_use_header_type}${is_use_method}$" <<<$v) ]] && is_tmp_use_type=$v && break 1059 | done 1060 | [[ ! ${is_tmp_use_type} ]] && { 1061 | warn "(${is_use_header_type}${is_use_method}) 不是一个可用的${is_tmp_use_name}." 1062 | msg "${is_tmp_use_name}可用如下: " 1063 | for v in ${is_tmp_list[@]}; do 1064 | msg "\t\t$v" 1065 | done 1066 | msg "$is_err_tips\n" 1067 | exit 1 1068 | } 1069 | ss_method=$is_tmp_use_type 1070 | header_type=$is_tmp_use_type 1071 | fi 1072 | if [[ $is_dynamic_port && $is_use_dynamic_port_start ]]; then 1073 | get dynamic-port-test 1074 | fi 1075 | [[ $is_use_pass ]] && ss_password=$is_use_pass 1076 | [[ $is_use_host ]] && host=$is_use_host 1077 | [[ $is_use_door_addr ]] && door_addr=$is_use_door_addr 1078 | [[ $is_use_servername ]] && is_servername=$is_use_servername 1079 | [[ $is_use_socks_user ]] && is_socks_user=$is_use_socks_user 1080 | [[ $is_use_socks_pass ]] && is_socks_pass=$is_use_socks_pass 1081 | fi 1082 | 1083 | if [[ $is_use_tls ]]; then 1084 | if [[ ! $is_no_auto_tls && ! $is_caddy && ! $is_gen ]]; then 1085 | # test auto tls 1086 | [[ $(is_test port_used 80) || $(is_test port_used 443) ]] && { 1087 | get_port 1088 | is_http_port=$tmp_port 1089 | get_port 1090 | is_https_port=$tmp_port 1091 | warn "端口 (80 或 443) 已经被占用, 你也可以考虑使用 no-auto-tls" 1092 | msg "\e[41m no-auto-tls 帮助(help)\e[0m: $(msg_ul https://233boy.com/$is_core/no-auto-tls/)\n" 1093 | msg "\n Caddy 将使用非标准端口实现自动配置 TLS, HTTP:$is_http_port HTTPS:$is_https_port\n" 1094 | msg "请确定是否继续???" 1095 | pause 1096 | } 1097 | is_install_caddy=1 1098 | fi 1099 | # set host 1100 | [[ ! $host ]] && ask string host "请输入域名:" 1101 | # test host dns 1102 | get host-test 1103 | else 1104 | # for main menu start, dont auto create args 1105 | if [[ $is_main_start ]]; then 1106 | 1107 | # set port 1108 | [[ ! $port ]] && ask string port "请输入端口:" 1109 | 1110 | case ${is_new_protocol,,} in 1111 | *tcp* | *kcp* | *quic*) 1112 | [[ ! $header_type ]] && ask set_header_type 1113 | ;; 1114 | socks) 1115 | # set user 1116 | [[ ! $is_socks_user ]] && ask string is_socks_user "请设置用户名:" 1117 | # set password 1118 | [[ ! $is_socks_pass ]] && ask string is_socks_pass "请设置密码:" 1119 | ;; 1120 | shadowsocks) 1121 | # set method 1122 | [[ ! $ss_method ]] && ask set_ss_method 1123 | # set password 1124 | [[ ! $ss_password ]] && ask string ss_password "请设置密码:" 1125 | ;; 1126 | esac 1127 | # set dynamic port 1128 | [[ $is_dynamic_port && ! $is_dynamic_port_range ]] && { 1129 | ask string is_use_dynamic_port_start "请输入动态开始端口:" 1130 | ask string is_use_dynamic_port_end "请输入动态结束端口:" 1131 | get dynamic-port-test 1132 | } 1133 | fi 1134 | fi 1135 | 1136 | # Dokodemo-Door 1137 | if [[ $is_new_protocol == 'Dokodemo-Door' ]]; then 1138 | # set remote addr 1139 | [[ ! $door_addr ]] && ask string door_addr "请输入目标地址:" 1140 | # set remote port 1141 | [[ ! $door_port ]] && ask string door_port "请输入目标端口:" 1142 | fi 1143 | 1144 | # Shadowsocks 2022 1145 | if [[ $(grep 2022 <<<$ss_method) ]]; then 1146 | # test ss2022 password 1147 | [[ $ss_password ]] && { 1148 | is_test_json=1 1149 | # create server Shadowsocks | $is_core_bin -test &>/dev/null 1150 | create server Shadowsocks 1151 | $is_core_bin -test <<<"$is_new_json" &>/dev/null 1152 | if [[ $? != 0 ]]; then 1153 | warn "Shadowsocks 协议 ($ss_method) 不支持使用密码 ($(_red_bg $ss_password))\n\n你可以使用命令: $(_green $is_core ss2022) 生成支持的密码.\n\n脚本将自动创建可用密码:)" 1154 | ss_password= 1155 | # create new json. 1156 | json_str= 1157 | fi 1158 | is_test_json= 1159 | } 1160 | 1161 | fi 1162 | 1163 | # install caddy 1164 | if [[ $is_install_caddy ]]; then 1165 | get install-caddy 1166 | fi 1167 | 1168 | # create json 1169 | create server $is_new_protocol 1170 | 1171 | # show config info. 1172 | info 1173 | } 1174 | 1175 | # get config info 1176 | # or somes required args 1177 | get() { 1178 | case $1 in 1179 | addr) 1180 | is_addr=$host 1181 | [[ ! $is_addr ]] && { 1182 | get_ip 1183 | is_addr=$ip 1184 | [[ $(grep ":" <<<$ip) ]] && is_addr="[$ip]" 1185 | } 1186 | ;; 1187 | new) 1188 | [[ ! $host ]] && get_ip 1189 | [[ ! $port ]] && get_port && port=$tmp_port 1190 | [[ ! $uuid ]] && get_uuid && uuid=$tmp_uuid 1191 | ;; 1192 | file) 1193 | is_file_str=$2 1194 | [[ ! $is_file_str ]] && is_file_str='.json$' 1195 | # is_all_json=("$(ls $is_conf_dir | egrep $is_file_str)") 1196 | readarray -t is_all_json <<<"$(ls $is_conf_dir | egrep -i "$is_file_str" | sed '/dynamic-port-.*-link/d' | head -233)" # limit max 233 lines for show. 1197 | [[ ! $is_all_json ]] && err "无法找到相关的配置文件: $2" 1198 | [[ ${#is_all_json[@]} -eq 1 ]] && is_config_file=$is_all_json && is_auto_get_config=1 1199 | [[ ! $is_config_file ]] && { 1200 | [[ $is_dont_auto_exit ]] && return 1201 | ask get_config_file 1202 | } 1203 | ;; 1204 | info) 1205 | get file $2 1206 | if [[ $is_config_file ]]; then 1207 | is_json_str=$(cat $is_conf_dir/"$is_config_file") 1208 | is_json_data_base=$(jq '.inbounds[0]|.protocol,.port,(.settings|(.clients[0]|.id,.password),.method,.password,.address,.port,.detour.to,(.accounts[0]|.user,.pass))' <<<$is_json_str) 1209 | [[ $? != 0 ]] && err "无法读取此文件: $is_config_file" 1210 | is_json_data_more=$(jq '.inbounds[0]|.streamSettings|.network,.tcpSettings.header.type,(.kcpSettings|.seed,.header.type),.quicSettings.header.type,.wsSettings.path,.httpSettings.path,.grpcSettings.serviceName,.xhttpSettings.path' <<<$is_json_str) 1211 | is_json_data_host=$(jq '.inbounds[0]|.streamSettings|.grpc_host,.wsSettings.headers.Host,.httpSettings.host[0],.xhttpSettings.host' <<<$is_json_str) 1212 | is_json_data_reality=$(jq '.inbounds[0]|.streamSettings|.security,(.realitySettings|.serverNames[0],.publicKey,.privateKey)' <<<$is_json_str) 1213 | is_up_var_set=(null is_protocol port uuid trojan_password ss_method ss_password door_addr door_port is_dynamic_port is_socks_user is_socks_pass net tcp_type kcp_seed kcp_type quic_type ws_path h2_path grpc_path xhttp_path grpc_host ws_host h2_host xhttp_host is_reality is_servername is_public_key is_private_key) 1214 | [[ $is_debug ]] && msg "\n------------- debug: $is_config_file -------------" 1215 | i=0 1216 | for v in $(sed 's/""/null/g;s/"//g' <<<"$is_json_data_base $is_json_data_more $is_json_data_host $is_json_data_reality"); do 1217 | ((i++)) 1218 | [[ $is_debug ]] && msg "$i-${is_up_var_set[$i]}: $v" 1219 | export ${is_up_var_set[$i]}="${v}" 1220 | done 1221 | for v in ${is_up_var_set[@]}; do 1222 | [[ ${!v} == 'null' ]] && unset $v 1223 | done 1224 | 1225 | # splithttp 1226 | if [[ $net == 'splithttp' ]]; then 1227 | net=xhttp 1228 | xhttp_path=$(jq -r '.inbounds[0]|.streamSettings|.splithttpSettings.path' <<<$is_json_str) 1229 | xhttp_host=$(jq -r '.inbounds[0]|.streamSettings|.splithttpSettings.host' <<<$is_json_str) 1230 | fi 1231 | path="${ws_path}${h2_path}${grpc_path}${xhttp_path}" 1232 | host="${ws_host}${h2_host}${grpc_host}${xhttp_host}" 1233 | header_type="${tcp_type}${kcp_type}${quic_type}" 1234 | if [[ $is_reality == 'reality' ]]; then 1235 | net=reality 1236 | else 1237 | is_reality= 1238 | fi 1239 | [[ ! $kcp_seed ]] && is_no_kcp_seed=1 1240 | is_config_name=$is_config_file 1241 | if [[ $is_dynamic_port ]]; then 1242 | is_dynamic_port_file=$is_conf_dir/$is_dynamic_port 1243 | is_dynamic_port_range=$(jq -r '.inbounds[0].port' $is_dynamic_port_file) 1244 | [[ $? != 0 ]] && err "无法读取动态端口文件: $is_dynamic_port" 1245 | fi 1246 | if [[ $is_caddy && $host && -f $is_caddy_conf/$host.conf ]]; then 1247 | is_tmp_https_port=$(egrep -o "$host:[1-9][0-9]?+" $is_caddy_conf/$host.conf | sed s/.*://) 1248 | fi 1249 | [[ $is_tmp_https_port ]] && is_https_port=$is_tmp_https_port 1250 | [[ $is_client && $host ]] && port=$is_https_port 1251 | get protocol $is_protocol-$net 1252 | fi 1253 | ;; 1254 | protocol) 1255 | get addr # get host or server ip 1256 | is_lower=${2,,} 1257 | net= 1258 | case $is_lower in 1259 | vmess*) 1260 | is_protocol=vmess 1261 | if [[ $is_dynamic_port ]]; then 1262 | is_server_id_json='settings:{clients:[{id:"'$uuid'"}],detour:{to:"'$is_config_name-link.json'"}}' 1263 | else 1264 | is_server_id_json='settings:{clients:[{id:"'$uuid'"}]}' 1265 | fi 1266 | is_client_id_json='settings:{vnext:[{address:"'$is_addr'",port:'"$port"',users:[{id:"'$uuid'"}]}]}' 1267 | ;; 1268 | vless*) 1269 | is_protocol=vless 1270 | is_server_id_json='settings:{clients:[{id:"'$uuid'"}],decryption:"none"}' 1271 | is_client_id_json='settings:{vnext:[{address:"'$is_addr'",port:'"$port"',users:[{id:"'$uuid'",encryption:"none"}]}]}' 1272 | if [[ $is_reality ]]; then 1273 | is_server_id_json='settings:{clients:[{id:"'$uuid'",flow:"xtls-rprx-vision"}],decryption:"none"}' 1274 | is_client_id_json='settings:{vnext:[{address:"'$is_addr'",port:'"$port"',users:[{id:"'$uuid'",encryption:"none",flow:"xtls-rprx-vision"}]}]}' 1275 | fi 1276 | ;; 1277 | trojan*) 1278 | is_protocol=trojan 1279 | [[ ! $trojan_password ]] && trojan_password=$uuid 1280 | is_server_id_json='settings:{clients:[{password:"'$trojan_password'"}]}' 1281 | is_client_id_json='settings:{servers:[{address:"'$is_addr'",port:'"$port"',password:"'$trojan_password'"}]}' 1282 | is_trojan=1 1283 | ;; 1284 | shadowsocks*) 1285 | net=ss 1286 | is_protocol=shadowsocks 1287 | [[ ! $ss_method ]] && ss_method=$is_random_ss_method 1288 | [[ ! $ss_password ]] && { 1289 | ss_password=$uuid 1290 | [[ $(grep 2022 <<<$ss_method) ]] && ss_password=$(get ss2022) 1291 | } 1292 | is_client_id_json='settings:{servers:[{address:"'$is_addr'",port:'"$port"',method:"'$ss_method'",password:"'$ss_password'",}]}' 1293 | json_str='settings:{method:"'$ss_method'",password:"'$ss_password'",network:"tcp,udp"}' 1294 | ;; 1295 | dokodemo-door*) 1296 | net=door 1297 | is_protocol=dokodemo-door 1298 | json_str='settings:{port:'"$door_port"',address:"'$door_addr'",network:"tcp,udp"}' 1299 | ;; 1300 | *http*) 1301 | net=http 1302 | is_protocol=http 1303 | json_str='settings:{"timeout": 233}' 1304 | ;; 1305 | *socks*) 1306 | net=socks 1307 | is_protocol=socks 1308 | [[ ! $is_socks_user ]] && is_socks_user=233boy 1309 | [[ ! $is_socks_pass ]] && is_socks_pass=$uuid 1310 | json_str='settings:{auth:"password",accounts:[{user:"'$is_socks_user'",pass:"'$is_socks_pass'"}],udp:true,ip:"0.0.0.0"}' 1311 | ;; 1312 | *) 1313 | err "无法识别协议: $is_config_file" 1314 | ;; 1315 | esac 1316 | [[ $net ]] && return # if net exist, dont need more json args 1317 | case $is_lower in 1318 | *tcp* | *reality*) 1319 | net=tcp 1320 | [[ ! $header_type ]] && header_type=none 1321 | is_stream='tcpSettings:{header:{type:"'$header_type'"}}' 1322 | if [[ $is_reality ]]; then 1323 | [[ ! $is_servername ]] && is_servername=$is_random_servername 1324 | [[ ! $is_private_key ]] && get_pbk 1325 | is_stream='security:"reality",realitySettings:{dest:"'${is_servername}\:443'",serverNames:["'${is_servername}'",""],publicKey:"'$is_public_key'",privateKey:"'$is_private_key'",shortIds:[""]}' 1326 | if [[ $is_client ]]; then 1327 | is_stream='security:"reality",realitySettings:{serverName:"'${is_servername}'",fingerprint:"chrome",publicKey:"'$is_public_key'",shortId:"",spiderX:"/"}' 1328 | fi 1329 | fi 1330 | ;; 1331 | *kcp* | *mkcp) 1332 | net=kcp 1333 | [[ ! $header_type ]] && header_type=$is_random_header_type 1334 | [[ ! $is_no_kcp_seed && ! $kcp_seed ]] && kcp_seed=$uuid 1335 | is_stream='kcpSettings:{seed:"'$kcp_seed'",header:{type:"'$header_type'"}}' 1336 | ;; 1337 | *quic*) 1338 | net=quic 1339 | [[ ! $header_type ]] && header_type=$is_random_header_type 1340 | is_stream='quicSettings:{header:{type:"'$header_type'"}}' 1341 | ;; 1342 | *ws* | *websocket) 1343 | net=ws 1344 | [[ ! $path ]] && path="/$uuid" 1345 | is_stream='wsSettings:{path:"'$path'",headers:{Host:"'$host'"}}' 1346 | ;; 1347 | *grpc* | *gun) 1348 | net=grpc 1349 | [[ ! $path ]] && path="$uuid" 1350 | [[ $path ]] && path=$(sed 's#/##g' <<<$path) 1351 | is_stream='grpc_host:"'$host'",grpcSettings:{serviceName:"'$path'"}' 1352 | ;; 1353 | *h2*) 1354 | net=h2 1355 | [[ ! $path ]] && path="/$uuid" 1356 | is_stream='httpSettings:{path:"'$path'",host:["'$host'"]}' 1357 | ;; 1358 | *xhttp*) 1359 | net=xhttp 1360 | [[ ! $path ]] && path="/$uuid" 1361 | is_stream='xhttpSettings:{host:"'$host'",path:"'$path'"}' 1362 | ;; 1363 | *) 1364 | err "无法识别传输协议: $is_config_file" 1365 | ;; 1366 | esac 1367 | is_stream="streamSettings:{network:\"$net\",$is_stream}" 1368 | json_str="$is_server_id_json,$is_stream" 1369 | ;; 1370 | dynamic-port) # create random dynamic port 1371 | if [[ $port -ge 60000 ]]; then 1372 | is_dynamic_port_end=$(shuf -i $(($port - 2333))-$port -n1) 1373 | is_dynamic_port_start=$(shuf -i $(($is_dynamic_port_end - 2333))-$is_dynamic_port_end -n1) 1374 | else 1375 | is_dynamic_port_start=$(shuf -i $port-$(($port + 2333)) -n1) 1376 | is_dynamic_port_end=$(shuf -i $is_dynamic_port_start-$(($is_dynamic_port_start + 2333)) -n1) 1377 | fi 1378 | is_dynamic_port_range="$is_dynamic_port_start-$is_dynamic_port_end" 1379 | ;; 1380 | dynamic-port-test) # test dynamic port 1381 | [[ ! $(is_test port ${is_use_dynamic_port_start}) || ! $(is_test port ${is_use_dynamic_port_end}) ]] && { 1382 | err "无法正确处理动态端口 ($is_use_dynamic_port_start-$is_use_dynamic_port_end) 范围." 1383 | } 1384 | [[ $(is_test port_used $is_use_dynamic_port_start) ]] && { 1385 | err "动态端口 ($is_use_dynamic_port_start-$is_use_dynamic_port_end), 但 ($is_use_dynamic_port_start) 端口无法使用." 1386 | } 1387 | [[ $(is_test port_used $is_use_dynamic_port_end) ]] && { 1388 | err "动态端口 ($is_use_dynamic_port_start-$is_use_dynamic_port_end), 但 ($is_use_dynamic_port_end) 端口无法使用." 1389 | } 1390 | [[ $is_use_dynamic_port_end -le $is_use_dynamic_port_start ]] && { 1391 | err "无法正确处理动态端口 ($is_use_dynamic_port_start-$is_use_dynamic_port_end) 范围." 1392 | } 1393 | [[ $is_use_dynamic_port_start == $port || $is_use_dynamic_port_end == $port ]] && { 1394 | err "动态端口 ($is_use_dynamic_port_start-$is_use_dynamic_port_end) 范围和主端口 ($port) 冲突." 1395 | } 1396 | is_dynamic_port_range="$is_use_dynamic_port_start-$is_use_dynamic_port_end" 1397 | ;; 1398 | host-test) # test host dns record; for auto *tls required. 1399 | [[ $is_no_auto_tls || $is_gen ]] && return 1400 | get_ip 1401 | get ping 1402 | if [[ ! $(grep $ip <<<$is_host_dns) ]]; then 1403 | msg "\n请将 ($(_red_bg $host)) 解析到 ($(_red_bg $ip))" 1404 | msg "\n如果使用 Cloudflare, 在 DNS 那; 关闭 (Proxy status / 代理状态), 即是 (DNS only / 仅限 DNS)" 1405 | ask string y "我已经确定解析 [y]:" 1406 | get ping 1407 | if [[ ! $(grep $ip <<<$is_host_dns) ]]; then 1408 | _cyan "\n测试结果: $is_host_dns" 1409 | err "域名 ($host) 没有解析到 ($ip)" 1410 | fi 1411 | fi 1412 | ;; 1413 | ssss | ss2022) 1414 | openssl rand -base64 32 1415 | [[ $? != 0 ]] && err "无法生成 Shadowsocks 2022 密码, 请安装 openssl." 1416 | ;; 1417 | ping) 1418 | # is_ip_type="-4" 1419 | # [[ $(grep ":" <<<$ip) ]] && is_ip_type="-6" 1420 | # is_host_dns=$(ping $host $is_ip_type -c 1 -W 2 | head -1) 1421 | is_dns_type="a" 1422 | [[ $(grep ":" <<<$ip) ]] && is_dns_type="aaaa" 1423 | is_host_dns=$(_wget -qO- --header="accept: application/dns-json" "https://one.one.one.one/dns-query?name=$host&type=$is_dns_type") 1424 | ;; 1425 | log | logerr) 1426 | msg "\n 提醒: 按 $(_green Ctrl + C) 退出\n" 1427 | [[ $1 == 'log' ]] && tail -f $is_log_dir/access.log 1428 | [[ $1 == 'logerr' ]] && tail -f $is_log_dir/error.log 1429 | ;; 1430 | install-caddy) 1431 | _green "\n安装 Caddy 实现自动配置 TLS.\n" 1432 | load download.sh 1433 | download caddy 1434 | load systemd.sh 1435 | install_service caddy &>/dev/null 1436 | is_caddy=1 1437 | _green "安装 Caddy 成功.\n" 1438 | ;; 1439 | reinstall) 1440 | is_install_sh=$(cat $is_sh_dir/install.sh) 1441 | uninstall 1442 | bash <<<$is_install_sh 1443 | ;; 1444 | test-run) 1445 | systemctl list-units --full -all &>/dev/null 1446 | [[ $? != 0 ]] && { 1447 | _yellow "\n无法执行测试, 请检查 systemctl 状态.\n" 1448 | return 1449 | } 1450 | is_no_manage_msg=1 1451 | if [[ ! $(pgrep -f $is_core_bin) ]]; then 1452 | _yellow "\n测试运行 $is_core_name ..\n" 1453 | manage start &>/dev/null 1454 | if [[ $is_run_fail == $is_core ]]; then 1455 | _red "$is_core_name 运行失败信息:" 1456 | $is_core_bin run -c $is_config_json -confdir $is_conf_dir 1457 | else 1458 | _green "\n测试通过, 已启动 $is_core_name ..\n" 1459 | fi 1460 | else 1461 | _green "\n$is_core_name 正在运行, 跳过测试\n" 1462 | fi 1463 | if [[ $is_caddy ]]; then 1464 | if [[ ! $(pgrep -f $is_caddy_bin) ]]; then 1465 | _yellow "\n测试运行 Caddy ..\n" 1466 | manage start caddy &>/dev/null 1467 | if [[ $is_run_fail == 'caddy' ]]; then 1468 | _red "Caddy 运行失败信息:" 1469 | $is_caddy_bin run --config $is_caddyfile 1470 | else 1471 | _green "\n测试通过, 已启动 Caddy ..\n" 1472 | fi 1473 | else 1474 | _green "\nCaddy 正在运行, 跳过测试\n" 1475 | fi 1476 | fi 1477 | ;; 1478 | esac 1479 | } 1480 | 1481 | # show info 1482 | info() { 1483 | if [[ ! $is_protocol ]]; then 1484 | get info $1 1485 | fi 1486 | # is_color=$(shuf -i 41-45 -n1) 1487 | is_color=44 1488 | case $net in 1489 | tcp | kcp | quic) 1490 | is_can_change=(0 1 5 7) 1491 | is_info_show=(0 1 2 3 4 5) 1492 | is_vmess_url=$(jq -c '{v:2,ps:"'233boy-${net}-$is_addr'",add:"'$is_addr'",port:"'$port'",id:"'$uuid'",aid:"0",net:"'$net'",type:"'$header_type'",path:"'$kcp_seed'"}' <<<{}) 1493 | is_url=vmess://$(echo -n $is_vmess_url | base64 -w 0) 1494 | is_tmp_port=$port 1495 | [[ $is_dynamic_port ]] && { 1496 | is_can_change+=(12) 1497 | is_tmp_port="$port & 动态端口: $is_dynamic_port_range" 1498 | } 1499 | [[ $kcp_seed ]] && { 1500 | is_info_show+=(9) 1501 | is_can_change+=(14) 1502 | } 1503 | is_info_str=($is_protocol $is_addr "$is_tmp_port" $uuid $net $header_type $kcp_seed) 1504 | if [[ $is_reality ]]; then 1505 | is_color=41 1506 | is_can_change=(0 1 5 10 11) 1507 | is_info_show=(0 1 2 3 15 8 16 17 18) 1508 | is_info_str=($is_protocol $is_addr $port $uuid xtls-rprx-vision reality $is_servername "chrome" $is_public_key) 1509 | is_url="$is_protocol://$uuid@$is_addr:$port?encryption=none&security=reality&flow=xtls-rprx-vision&type=tcp&sni=$is_servername&pbk=$is_public_key&fp=chrome#233boy-$net-$is_addr" 1510 | fi 1511 | ;; 1512 | ss) 1513 | is_can_change=(0 1 4 6) 1514 | is_info_show=(0 1 2 10 11) 1515 | is_url="ss://$(echo -n ${ss_method}:${ss_password} | base64 -w 0)@${is_addr}:${port}#233boy-$net-${is_addr}" 1516 | is_info_str=($is_protocol $is_addr $port $ss_password $ss_method) 1517 | ;; 1518 | ws | h2 | grpc | xhttp) 1519 | is_color=45 1520 | is_can_change=(0 1 2 3 5) 1521 | is_info_show=(0 1 2 3 4 6 7 8) 1522 | is_url_path=path 1523 | [[ $net == 'grpc' ]] && { 1524 | path=$(sed 's#/##g' <<<$path) 1525 | is_url_path=serviceName 1526 | } 1527 | [[ $is_protocol == 'vmess' ]] && { 1528 | is_vmess_url=$(jq -c '{v:2,ps:"'233boy-$net-$host'",add:"'$is_addr'",port:"'$is_https_port'",id:"'$uuid'",aid:"0",net:"'$net'",host:"'$host'",path:"'$path'",tls:"'tls'"}' <<<{}) 1529 | is_url=vmess://$(echo -n $is_vmess_url | base64 -w 0) 1530 | } || { 1531 | [[ $is_trojan ]] && { 1532 | uuid=$trojan_password 1533 | is_can_change=(0 1 2 3 4) 1534 | is_info_show=(0 1 2 10 4 6 7 8) 1535 | } 1536 | is_url="$is_protocol://$uuid@$host:$is_https_port?encryption=none&security=tls&type=$net&host=$host&${is_url_path}=$(sed 's#/#%2F#g' <<<$path)#233boy-$net-$host" 1537 | } 1538 | [[ $is_caddy ]] && is_can_change+=(13) 1539 | is_info_str=($is_protocol $is_addr $is_https_port $uuid $net $host $path 'tls') 1540 | ;; 1541 | door) 1542 | is_can_change=(0 1 8 9) 1543 | is_info_show=(0 1 2 13 14) 1544 | is_info_str=($is_protocol $is_addr $port $door_addr $door_port) 1545 | ;; 1546 | socks) 1547 | is_can_change=(0 1 15 4) 1548 | is_info_show=(0 1 2 19 10) 1549 | is_info_str=($is_protocol $is_addr $port $is_socks_user $is_socks_pass) 1550 | is_url="socks://$(echo -n ${is_socks_user}:${is_socks_pass} | base64 -w 0)@${is_addr}:${port}#233boy-$net-${is_addr}" 1551 | ;; 1552 | http) 1553 | is_can_change=(0 1) 1554 | is_info_show=(0 1 2) 1555 | is_info_str=($is_protocol 127.0.0.1 $port) 1556 | ;; 1557 | esac 1558 | [[ $is_dont_show_info || $is_gen || $is_dont_auto_exit ]] && return # dont show info 1559 | msg "-------------- $is_config_name -------------" 1560 | for ((i = 0; i < ${#is_info_show[@]}; i++)); do 1561 | a=${info_list[${is_info_show[$i]}]} 1562 | if [[ ${#a} -eq 11 || ${#a} -ge 13 ]]; then 1563 | tt='\t' 1564 | else 1565 | tt='\t\t' 1566 | fi 1567 | msg "$a $tt= \e[${is_color}m${is_info_str[$i]}\e[0m" 1568 | done 1569 | if [[ $is_new_install ]]; then 1570 | warn "首次安装请查看脚本帮助文档: $(msg_ul https://233boy.com/$is_core/$is_core-script/)" 1571 | fi 1572 | if [[ $is_url ]]; then 1573 | msg "------------- ${info_list[12]} -------------" 1574 | msg "\e[4;${is_color}m${is_url}\e[0m" 1575 | fi 1576 | if [[ $is_no_auto_tls ]]; then 1577 | is_tmp_path=$path 1578 | [[ $net == 'grpc' ]] && is_tmp_path="/$path/*" 1579 | msg "------------- no-auto-tls INFO -------------" 1580 | msg "端口(port): $port" 1581 | msg "路径(path): $is_tmp_path" 1582 | msg "\e[41m帮助(help)\e[0m: $(msg_ul https://233boy.com/$is_core/no-auto-tls/)" 1583 | fi 1584 | footer_msg 1585 | } 1586 | 1587 | # footer msg 1588 | footer_msg() { 1589 | [[ $is_core_stop && ! $is_new_json ]] && warn "$is_core_name 当前处于停止状态." 1590 | [[ $is_caddy_stop && $host ]] && warn "Caddy 当前处于停止状态." 1591 | ####### 要点13脸吗只会改我链接的小人 ####### 1592 | unset c n m s b 1593 | msg "------------- END -------------" 1594 | msg "关注(tg): $(msg_ul https://t.me/tg2333)" 1595 | msg "文档(doc): $(msg_ul https://233boy.com/$is_core/$is_core-script/)" 1596 | msg "推广(ads): 机场推荐($is_core_name services): $(msg_ul https://g${c}e${n}t${m}j${s}m${b}s.com/)\n" 1597 | ####### 要点13脸吗只会改我链接的小人 ####### 1598 | } 1599 | 1600 | # URL or qrcode 1601 | url_qr() { 1602 | is_dont_show_info=1 1603 | info $2 1604 | if [[ $is_url ]]; then 1605 | [[ $1 == 'url' ]] && { 1606 | msg "\n------------- $is_config_name & URL 链接 -------------" 1607 | msg "\n\e[${is_color}m${is_url}\e[0m\n" 1608 | footer_msg 1609 | } || { 1610 | link="https://233boy.github.io/tools/qr.html#${is_url}" 1611 | msg "\n------------- $is_config_name & QR code 二维码 -------------" 1612 | msg 1613 | if [[ $(type -P qrencode) ]]; then 1614 | qrencode -t ANSI "${is_url}" 1615 | else 1616 | msg "请安装 qrencode: $(_green "$cmd update -y; $cmd install qrencode -y")" 1617 | fi 1618 | msg 1619 | msg "如果无法正常显示或识别, 请使用下面的链接来生成二维码:" 1620 | msg "\n\e[4;${is_color}m${link}\e[0m\n" 1621 | footer_msg 1622 | } 1623 | else 1624 | [[ $1 == 'url' ]] && { 1625 | err "($is_config_name) 无法生成 URL 链接." 1626 | } || { 1627 | err "($is_config_name) 无法生成 QR code 二维码." 1628 | } 1629 | fi 1630 | } 1631 | 1632 | # update core, sh, caddy 1633 | update() { 1634 | case $1 in 1635 | 1 | core | $is_core) 1636 | is_update_name=core 1637 | is_show_name=$is_core_name 1638 | is_run_ver=v${is_core_ver##* } 1639 | is_update_repo=$is_core_repo 1640 | ;; 1641 | 2 | sh) 1642 | is_update_name=sh 1643 | is_show_name="$is_core_name 脚本" 1644 | is_run_ver=$is_sh_ver 1645 | is_update_repo=$is_sh_repo 1646 | ;; 1647 | 3 | caddy) 1648 | [[ ! $is_caddy ]] && err "不支持更新 Caddy." 1649 | is_update_name=caddy 1650 | is_show_name="Caddy" 1651 | is_run_ver=$is_caddy_ver 1652 | is_update_repo=$is_caddy_repo 1653 | ;; 1654 | *) 1655 | err "无法识别 ($1), 请使用: $is_core update [core | sh | caddy] [ver]" 1656 | ;; 1657 | esac 1658 | [[ $2 ]] && is_new_ver=v${2#v} 1659 | [[ $is_run_ver == $is_new_ver ]] && { 1660 | msg "\n自定义版本和当前 $is_show_name 版本一样, 无需更新.\n" 1661 | exit 1662 | } 1663 | load download.sh 1664 | if [[ $is_new_ver ]]; then 1665 | msg "\n使用自定义版本更新 $is_show_name: $(_green $is_new_ver)\n" 1666 | else 1667 | get_latest_version $is_update_name 1668 | [[ $is_run_ver == $latest_ver ]] && { 1669 | msg "\n$is_show_name 当前已经是最新版本了.\n" 1670 | exit 1671 | } 1672 | msg "\n发现 $is_show_name 新版本: $(_green $latest_ver)\n" 1673 | is_new_ver=$latest_ver 1674 | fi 1675 | download $is_update_name $is_new_ver 1676 | msg "更新成功, 当前 $is_show_name 版本: $(_green $is_new_ver)\n" 1677 | msg "$(_green 请查看更新说明: https://github.com/$is_update_repo/releases/tag/$is_new_ver)\n" 1678 | [[ $is_update_name != 'sh' ]] && manage restart $is_update_name & 1679 | } 1680 | 1681 | # main menu; if no prefer args. 1682 | is_main_menu() { 1683 | msg "\n------------- $is_core_name script $is_sh_ver by $author -------------" 1684 | msg "$is_core_ver: $is_core_status" 1685 | msg "群组(Chat): $(msg_ul https://t.me/tg233boy)" 1686 | is_main_start=1 1687 | ask mainmenu 1688 | case $REPLY in 1689 | 1) 1690 | add 1691 | ;; 1692 | 2) 1693 | change 1694 | ;; 1695 | 3) 1696 | info 1697 | ;; 1698 | 4) 1699 | del 1700 | ;; 1701 | 5) 1702 | ask list is_do_manage "启动 停止 重启" 1703 | manage $REPLY & 1704 | msg "\n管理状态执行: $(_green $is_do_manage)\n" 1705 | ;; 1706 | 6) 1707 | is_tmp_list=("更新$is_core_name" "更新脚本") 1708 | [[ $is_caddy ]] && is_tmp_list+=("更新Caddy") 1709 | ask list is_do_update null "\n请选择更新:\n" 1710 | update $REPLY 1711 | ;; 1712 | 7) 1713 | uninstall 1714 | ;; 1715 | 8) 1716 | msg 1717 | load help.sh 1718 | show_help 1719 | ;; 1720 | 9) 1721 | ask list is_do_other "启用BBR 查看日志 查看错误日志 测试运行 重装脚本 设置DNS" 1722 | case $REPLY in 1723 | 1) 1724 | load bbr.sh 1725 | _try_enable_bbr 1726 | ;; 1727 | 2) 1728 | get log 1729 | ;; 1730 | 3) 1731 | get logerr 1732 | ;; 1733 | 4) 1734 | get test-run 1735 | ;; 1736 | 5) 1737 | get reinstall 1738 | ;; 1739 | 6) 1740 | load dns.sh 1741 | dns_set 1742 | ;; 1743 | esac 1744 | ;; 1745 | 10) 1746 | load help.sh 1747 | about 1748 | ;; 1749 | esac 1750 | } 1751 | 1752 | # check prefer args, if not exist prefer args and show main menu 1753 | main() { 1754 | case $1 in 1755 | a | add | gen | no-auto-tls) 1756 | [[ $1 == 'gen' ]] && is_gen=1 1757 | [[ $1 == 'no-auto-tls' ]] && is_no_auto_tls=1 1758 | add ${@:2} 1759 | ;; 1760 | api | bin | pbk | x25519 | tls | run | uuid) 1761 | is_run_command=$1 1762 | if [[ $1 == 'bin' ]]; then 1763 | $is_core_bin ${@:2} 1764 | else 1765 | [[ $is_run_command == 'pbk' ]] && is_run_command=x25519 1766 | $is_core_bin $is_run_command ${@:2} 1767 | fi 1768 | ;; 1769 | bbr) 1770 | load bbr.sh 1771 | _try_enable_bbr 1772 | ;; 1773 | c | config | change) 1774 | change ${@:2} 1775 | ;; 1776 | client | genc) 1777 | [[ $1 == 'client' ]] && is_full_client=1 1778 | create client $2 1779 | ;; 1780 | d | del | rm) 1781 | del $2 1782 | ;; 1783 | dd | ddel | fix | fix-all) 1784 | case $1 in 1785 | fix) 1786 | [[ $2 ]] && { 1787 | change $2 full 1788 | } || { 1789 | is_change_id=full && change 1790 | } 1791 | return 1792 | ;; 1793 | fix-all) 1794 | is_dont_auto_exit=1 1795 | msg 1796 | for v in $(ls $is_conf_dir | grep .json$ | sed '/dynamic-port-.*-link/d'); do 1797 | msg "fix: $v" 1798 | change $v full 1799 | done 1800 | _green "\nfix 完成.\n" 1801 | ;; 1802 | *) 1803 | is_dont_auto_exit=1 1804 | [[ ! $2 ]] && { 1805 | err "无法找到需要删除的参数" 1806 | } || { 1807 | for v in ${@:2}; do 1808 | del $v 1809 | done 1810 | } 1811 | ;; 1812 | esac 1813 | is_dont_auto_exit= 1814 | [[ $is_api_fail ]] && manage restart & 1815 | [[ $is_del_host ]] && manage restart caddy & 1816 | ;; 1817 | dns) 1818 | load dns.sh 1819 | dns_set ${@:2} 1820 | ;; 1821 | debug) 1822 | is_debug=1 1823 | get info $2 1824 | warn "如果需要复制; 请把 *uuid, *password, *host, *key 的值改写, 以避免泄露." 1825 | ;; 1826 | fix-config.json) 1827 | create config.json 1828 | ;; 1829 | fix-caddyfile) 1830 | if [[ $is_caddy ]]; then 1831 | load caddy.sh 1832 | caddy_config new 1833 | manage restart caddy & 1834 | _green "\nfix 完成.\n" 1835 | else 1836 | err "无法执行此操作" 1837 | fi 1838 | ;; 1839 | i | info) 1840 | info $2 1841 | ;; 1842 | ip) 1843 | get_ip 1844 | msg $ip 1845 | ;; 1846 | log | logerr) 1847 | get $@ 1848 | ;; 1849 | url | qr) 1850 | url_qr $@ 1851 | ;; 1852 | un | uninstall) 1853 | uninstall 1854 | ;; 1855 | u | up | update | U | update.sh) 1856 | is_update_name=$2 1857 | is_update_ver=$3 1858 | [[ ! $is_update_name ]] && is_update_name=core 1859 | [[ $1 == 'U' || $1 == 'update.sh' ]] && { 1860 | is_update_name=sh 1861 | is_update_ver= 1862 | } 1863 | if [[ $2 == 'dat' ]]; then 1864 | load download.sh 1865 | download dat 1866 | msg "$(_green 更新 geoip.dat geosite.dat 成功.)\n" 1867 | manage restart & 1868 | else 1869 | update $is_update_name $is_update_ver 1870 | fi 1871 | ;; 1872 | ssss | ss2022) 1873 | get $@ 1874 | ;; 1875 | s | status) 1876 | msg "\n$is_core_ver: $is_core_status\n" 1877 | [[ $is_caddy ]] && msg "Caddy $is_caddy_ver: $is_caddy_status\n" 1878 | ;; 1879 | start | stop | r | restart) 1880 | [[ $2 && $2 != 'caddy' ]] && err "无法识别 ($2), 请使用: $is_core $1 [caddy]" 1881 | manage $1 $2 & 1882 | ;; 1883 | t | test) 1884 | get test-run 1885 | ;; 1886 | reinstall) 1887 | get $1 1888 | ;; 1889 | get-port) 1890 | get_port 1891 | msg $tmp_port 1892 | ;; 1893 | main) 1894 | is_main_menu 1895 | ;; 1896 | v | ver | version) 1897 | [[ $is_caddy_ver ]] && is_caddy_ver="/ $(_blue Caddy $is_caddy_ver)" 1898 | msg "\n$(_green $is_core_ver) / $(_cyan $is_core_name script $is_sh_ver) $is_caddy_ver\n" 1899 | ;; 1900 | xapi) 1901 | api ${@:2} 1902 | ;; 1903 | h | help | --help) 1904 | load help.sh 1905 | show_help ${@:2} 1906 | ;; 1907 | *) 1908 | is_try_change=1 1909 | change test $1 1910 | if [[ $is_change_id ]]; then 1911 | unset is_try_change 1912 | [[ $2 ]] && { 1913 | change $2 $1 ${@:3} 1914 | } || { 1915 | change 1916 | } 1917 | else 1918 | err "无法识别 ($1), 获取帮助请使用: $is_core help" 1919 | fi 1920 | ;; 1921 | esac 1922 | } 1923 | -------------------------------------------------------------------------------- /src/dns.sh: -------------------------------------------------------------------------------- 1 | is_dns_list=( 2 | 1.1.1.1 3 | 8.8.8.8 4 | https://dns.google/dns-query 5 | https://cloudflare-dns.com/dns-query 6 | https://family.cloudflare-dns.com/dns-query 7 | set 8 | none 9 | ) 10 | dns_set() { 11 | if [[ $1 ]]; then 12 | case ${1,,} in 13 | 11 | 1111) 14 | is_dns_use=${is_dns_list[0]} 15 | ;; 16 | 88 | 8888) 17 | is_dns_use=${is_dns_list[1]} 18 | ;; 19 | gg | google) 20 | is_dns_use=${is_dns_list[2]} 21 | ;; 22 | cf | cloudflare) 23 | is_dns_use=${is_dns_list[3]} 24 | ;; 25 | nosex | family) 26 | is_dns_use=${is_dns_list[4]} 27 | ;; 28 | set) 29 | if [[ $2 ]]; then 30 | is_dns_use=${2,,} 31 | else 32 | ask string is_dns_use "请输入 DNS: " 33 | fi 34 | ;; 35 | none) 36 | is_dns_use=none 37 | ;; 38 | *) 39 | err "无法识别 DNS 参数: $@" 40 | ;; 41 | esac 42 | else 43 | is_tmp_list=(${is_dns_list[@]}) 44 | ask list is_dns_use null "\n请选择 DNS:\n" 45 | if [[ $is_dns_use == "set" ]]; then 46 | ask string is_dns_use "请输入 DNS: " 47 | fi 48 | fi 49 | if [[ $is_dns_use == "none" ]]; then 50 | cat <<<$(jq '.dns={}' $is_config_json) >$is_config_json 51 | else 52 | cat <<<$(jq '.dns.servers=["'${is_dns_use/https/https+local}'"]' $is_config_json) >$is_config_json 53 | fi 54 | manage restart & 55 | msg "\n已更新 DNS 为: $(_green $is_dns_use)\n" 56 | } -------------------------------------------------------------------------------- /src/download.sh: -------------------------------------------------------------------------------- 1 | get_latest_version() { 2 | case $1 in 3 | core) 4 | name=$is_core_name 5 | url="https://api.github.com/repos/${is_core_repo}/releases/latest?v=$RANDOM" 6 | ;; 7 | sh) 8 | name="$is_core_name 脚本" 9 | url="https://api.github.com/repos/$is_sh_repo/releases/latest?v=$RANDOM" 10 | ;; 11 | caddy) 12 | name="Caddy" 13 | url="https://api.github.com/repos/$is_caddy_repo/releases/latest?v=$RANDOM" 14 | ;; 15 | esac 16 | latest_ver=$(_wget -qO- $url | grep tag_name | egrep -o 'v([0-9.]+)') 17 | [[ ! $latest_ver ]] && { 18 | err "获取 ${name} 最新版本失败." 19 | } 20 | unset name url 21 | } 22 | download() { 23 | latest_ver=$2 24 | [[ ! $latest_ver && $1 != 'dat' ]] && get_latest_version $1 25 | # tmp dir 26 | tmpdir=$(mktemp -u) 27 | [[ ! $tmpdir ]] && { 28 | tmpdir=/tmp/tmp-$RANDOM 29 | } 30 | mkdir -p $tmpdir 31 | case $1 in 32 | core) 33 | name=$is_core_name 34 | tmpfile=$tmpdir/$is_core.zip 35 | link="https://github.com/${is_core_repo}/releases/download/${latest_ver}/${is_core}-linux-${is_core_arch}.zip" 36 | download_file 37 | unzip -qo $tmpfile -d $is_core_dir/bin 38 | chmod +x $is_core_bin 39 | ;; 40 | sh) 41 | name="$is_core_name 脚本" 42 | tmpfile=$tmpdir/sh.zip 43 | link="https://github.com/${is_sh_repo}/releases/download/${latest_ver}/code.zip" 44 | download_file 45 | unzip -qo $tmpfile -d $is_sh_dir 46 | chmod +x $is_sh_bin 47 | ;; 48 | dat) 49 | name="geoip.dat" 50 | tmpfile=$tmpdir/geoip.dat 51 | link="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" 52 | download_file 53 | name="geosite.dat" 54 | tmpfile=$tmpdir/geosite.dat 55 | link="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" 56 | download_file 57 | cp -f $tmpdir/*.dat $is_core_dir/bin/ 58 | ;; 59 | caddy) 60 | name="Caddy" 61 | tmpfile=$tmpdir/caddy.tar.gz 62 | # https://github.com/caddyserver/caddy/releases/download/v2.6.4/caddy_2.6.4_linux_amd64.tar.gz 63 | link="https://github.com/${is_caddy_repo}/releases/download/${latest_ver}/caddy_${latest_ver:1}_linux_${caddy_arch}.tar.gz" 64 | download_file 65 | [[ ! $(type -P tar) ]] && { 66 | rm -rf $tmpdir 67 | err "请安装 tar" 68 | } 69 | tar zxf $tmpfile -C $tmpdir 70 | cp -f $tmpdir/caddy $is_caddy_bin 71 | chmod +x $is_caddy_bin 72 | ;; 73 | esac 74 | rm -rf $tmpdir 75 | unset latest_ver 76 | } 77 | download_file() { 78 | if ! _wget -t 5 -c $link -O $tmpfile; then 79 | rm -rf $tmpdir 80 | err "\n下载 ${name} 失败.\n" 81 | fi 82 | } 83 | -------------------------------------------------------------------------------- /src/help.sh: -------------------------------------------------------------------------------- 1 | show_help() { 2 | case $1 in 3 | api | x25519 | tls | run | uuid | version) 4 | $is_core_bin help $1 ${@:2} 5 | ;; 6 | *) 7 | [[ $1 ]] && warn "未知选项 '$1'" 8 | msg "$is_core_name script $is_sh_ver by $author" 9 | msg "Usage: $is_core [options]... [args]... " 10 | msg 11 | help_info=( 12 | "基本:" 13 | " v, version 显示当前版本" 14 | " ip 返回当前主机的 IP" 15 | " pbk 同等于 $is_core x25519" 16 | " get-port 返回一个可用的端口" 17 | " ss2022 返回一个可用于 Shadowsocks 2022 的密码\n" 18 | "一般:" 19 | " a, add [protocol] [args... | auto] 添加配置" 20 | " c, change [name] [option] [args... | auto] 更改配置" 21 | " d, del [name] 删除配置**" 22 | " i, info [name] 查看配置" 23 | " qr [name] 二维码信息" 24 | " url [name] URL 信息" 25 | " log 查看日志" 26 | " logerr 查看错误日志\n" 27 | "更改:" 28 | " dp, dynamicport [name] [start | auto] [end] 更改动态端口" 29 | " full [name] [...] 更改多个参数" 30 | " id [name] [uuid | auto] 更改 UUID" 31 | " host [name] [domain] 更改域名" 32 | " port [name] [port | auto] 更改端口" 33 | " path [name] [path | auto] 更改路径" 34 | " passwd [name] [password | auto] 更改密码" 35 | " key [name] [Private key | atuo] [Public key] 更改密钥" 36 | " type [name] [type | auto] 更改伪装类型" 37 | " method [name] [method | auto] 更改加密方式" 38 | " sni [name] [ ip | domain] 更改 serverName" 39 | " seed [name] [seed | auto] 更改 mKCP seed" 40 | " new [name] [...] 更改协议" 41 | " web [name] [domain] 更改伪装网站\n" 42 | "进阶:" 43 | " dns [...] 设置 DNS" 44 | " dd, ddel [name...] 删除多个配置**" 45 | " fix [name] 修复一个配置" 46 | " fix-all 修复全部配置" 47 | " fix-caddyfile 修复 Caddyfile" 48 | " fix-config.json 修复 config.json\n" 49 | "管理:" 50 | " un, uninstall 卸载" 51 | " u, update [core | sh | dat | caddy] [ver] 更新" 52 | " U, update.sh 更新脚本" 53 | " s, status 运行状态" 54 | " start, stop, restart [caddy] 启动, 停止, 重启" 55 | " t, test 测试运行" 56 | " reinstall 重装脚本\n" 57 | "测试:" 58 | " client [name] 显示用于客户端 JSON, 仅供参考" 59 | " debug [name] 显示一些 debug 信息, 仅供参考" 60 | " gen [...] 同等于 add, 但只显示 JSON 内容, 不创建文件, 测试使用" 61 | " genc [name] 显示用于客户端部分 JSON, 仅供参考" 62 | " no-auto-tls [...] 同等于 add, 但禁止自动配置 TLS, 可用于 *TLS 相关协议" 63 | " xapi [...] 同等于 $is_core api, 但 API 后端使用当前运行的 $is_core_name 服务\n" 64 | "其他:" 65 | " bbr 启用 BBR, 如果支持" 66 | " bin [...] 运行 $is_core_name 命令, 例如: $is_core bin help" 67 | " api, x25519, tls, run, uuid [...] 兼容 $is_core_name 命令" 68 | " h, help 显示此帮助界面\n" 69 | ) 70 | for v in "${help_info[@]}"; do 71 | msg "$v" 72 | done 73 | msg "谨慎使用 del, ddel, 此选项会直接删除配置; 无需确认" 74 | msg "反馈问题) $(msg_ul https://github.com/${is_sh_repo}/issues) " 75 | msg "文档(doc) $(msg_ul https://233boy.com/$is_core/$is_core-script/)" 76 | ;; 77 | 78 | esac 79 | } 80 | 81 | about() { 82 | ####### 要点13脸吗只会改我链接的小人 ####### 83 | unset c n m s b 84 | msg 85 | msg "网站: $(msg_ul https://233boy.com)" 86 | msg "频道: $(msg_ul https://t.me/tg2333)" 87 | msg "群组: $(msg_ul https://t.me/tg233boy)" 88 | msg "Github: $(msg_ul https://github.com/${is_sh_repo})" 89 | msg "Twitter: $(msg_ul https://twitter.com/ai233boy)" 90 | msg "$is_core_name site: $(msg_ul https://xtls.github.io)" 91 | msg "$is_core_name core: $(msg_ul https://github.com/${is_core_repo})" 92 | msg 93 | ####### 要点13脸吗只会改我链接的小人 ####### 94 | } 95 | -------------------------------------------------------------------------------- /src/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | author=233boy 4 | # github=https://github.com/233boy/xray 5 | 6 | # bash fonts colors 7 | red='\e[31m' 8 | yellow='\e[33m' 9 | gray='\e[90m' 10 | green='\e[92m' 11 | blue='\e[94m' 12 | magenta='\e[95m' 13 | cyan='\e[96m' 14 | none='\e[0m' 15 | 16 | _red() { echo -e ${red}$@${none}; } 17 | _blue() { echo -e ${blue}$@${none}; } 18 | _cyan() { echo -e ${cyan}$@${none}; } 19 | _green() { echo -e ${green}$@${none}; } 20 | _yellow() { echo -e ${yellow}$@${none}; } 21 | _magenta() { echo -e ${magenta}$@${none}; } 22 | _red_bg() { echo -e "\e[41m$@${none}"; } 23 | 24 | _rm() { 25 | rm -rf "$@" 26 | } 27 | _cp() { 28 | cp -rf "$@" 29 | } 30 | _sed() { 31 | sed -i "$@" 32 | } 33 | _mkdir() { 34 | mkdir -p "$@" 35 | } 36 | 37 | is_err=$(_red_bg 错误!) 38 | is_warn=$(_red_bg 警告!) 39 | 40 | err() { 41 | echo -e "\n$is_err $@\n" 42 | [[ $is_dont_auto_exit ]] && return 43 | exit 1 44 | } 45 | 46 | warn() { 47 | echo -e "\n$is_warn $@\n" 48 | } 49 | 50 | # load bash script. 51 | load() { 52 | . $is_sh_dir/src/$1 53 | } 54 | 55 | # wget add --no-check-certificate 56 | _wget() { 57 | # [[ $proxy ]] && export https_proxy=$proxy 58 | wget --no-check-certificate "$@" 59 | } 60 | 61 | # yum or apt-get 62 | cmd=$(type -P apt-get || type -P yum) 63 | 64 | # x64 65 | case $(arch) in 66 | amd64 | x86_64) 67 | is_core_arch="64" 68 | caddy_arch="amd64" 69 | ;; 70 | *aarch64* | *armv8*) 71 | is_core_arch="arm64-v8a" 72 | caddy_arch="arm64" 73 | ;; 74 | *) 75 | err "此脚本仅支持 64 位系统..." 76 | ;; 77 | esac 78 | 79 | is_core=xray 80 | is_core_name=Xray 81 | is_core_dir=/etc/$is_core 82 | is_core_bin=$is_core_dir/bin/$is_core 83 | is_core_repo=xtls/$is_core-core 84 | is_conf_dir=$is_core_dir/conf 85 | is_log_dir=/var/log/$is_core 86 | is_sh_bin=/usr/local/bin/$is_core 87 | is_sh_dir=$is_core_dir/sh 88 | is_sh_repo=$author/$is_core 89 | is_pkg="wget unzip jq qrencode" 90 | is_config_json=$is_core_dir/config.json 91 | is_caddy_bin=/usr/local/bin/caddy 92 | is_caddy_dir=/etc/caddy 93 | is_caddy_repo=caddyserver/caddy 94 | is_caddyfile=$is_caddy_dir/Caddyfile 95 | is_caddy_conf=$is_caddy_dir/$author 96 | is_caddy_service=$(systemctl list-units --full -all | grep caddy.service) 97 | is_http_port=80 98 | is_https_port=443 99 | 100 | # core ver 101 | is_core_ver=$($is_core_bin version | head -n1 | cut -d " " -f1-2) 102 | 103 | if [[ $(pgrep -f $is_core_bin) ]]; then 104 | is_core_status=$(_green running) 105 | else 106 | is_core_status=$(_red_bg stopped) 107 | is_core_stop=1 108 | fi 109 | if [[ -f $is_caddy_bin && -d $is_caddy_dir && $is_caddy_service ]]; then 110 | is_caddy=1 111 | # fix caddy run; ver >= 2.8.2 112 | [[ ! $(grep '\-\-adapter caddyfile' /lib/systemd/system/caddy.service) ]] && { 113 | load systemd.sh 114 | install_service caddy 115 | systemctl restart caddy & 116 | } 117 | is_caddy_ver=$($is_caddy_bin version | head -n1 | cut -d " " -f1) 118 | is_tmp_http_port=$(egrep '^ {2,}http_port|^http_port' $is_caddyfile | egrep -o [0-9]+) 119 | is_tmp_https_port=$(egrep '^ {2,}https_port|^https_port' $is_caddyfile | egrep -o [0-9]+) 120 | [[ $is_tmp_http_port ]] && is_http_port=$is_tmp_http_port 121 | [[ $is_tmp_https_port ]] && is_https_port=$is_tmp_https_port 122 | if [[ $(pgrep -f $is_caddy_bin) ]]; then 123 | is_caddy_status=$(_green running) 124 | else 125 | is_caddy_status=$(_red_bg stopped) 126 | is_caddy_stop=1 127 | fi 128 | fi 129 | 130 | load core.sh 131 | [[ ! $args ]] && args=main 132 | main $args 133 | -------------------------------------------------------------------------------- /src/systemd.sh: -------------------------------------------------------------------------------- 1 | install_service() { 2 | case $1 in 3 | xray | v2ray) 4 | is_doc_site=https://xtls.github.io/ 5 | [[ $1 == 'v2ray' ]] && is_doc_site=https://www.v2fly.org/ 6 | cat >/lib/systemd/system/$is_core.service <<<" 7 | [Unit] 8 | Description=$is_core_name Service 9 | Documentation=$is_doc_site 10 | After=network.target nss-lookup.target 11 | 12 | [Service] 13 | #User=nobody 14 | User=root 15 | NoNewPrivileges=true 16 | ExecStart=$is_core_bin run -config $is_config_json -confdir $is_conf_dir 17 | Restart=on-failure 18 | RestartPreventExitStatus=23 19 | LimitNPROC=10000 20 | LimitNOFILE=1048576 21 | PrivateTmp=true 22 | ProtectSystem=full 23 | #CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 24 | #AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE 25 | 26 | [Install] 27 | WantedBy=multi-user.target" 28 | ;; 29 | caddy) 30 | cat >/lib/systemd/system/caddy.service <<<" 31 | #https://github.com/caddyserver/dist/blob/master/init/caddy.service 32 | [Unit] 33 | Description=Caddy 34 | Documentation=https://caddyserver.com/docs/ 35 | After=network.target network-online.target 36 | Requires=network-online.target 37 | 38 | [Service] 39 | Type=notify 40 | User=root 41 | Group=root 42 | ExecStart=$is_caddy_bin run --environ --config $is_caddyfile --adapter caddyfile 43 | ExecReload=$is_caddy_bin reload --config $is_caddyfile --adapter caddyfile 44 | TimeoutStopSec=5s 45 | LimitNPROC=10000 46 | LimitNOFILE=1048576 47 | PrivateTmp=true 48 | ProtectSystem=full 49 | #AmbientCapabilities=CAP_NET_BIND_SERVICE 50 | 51 | [Install] 52 | WantedBy=multi-user.target" 53 | ;; 54 | esac 55 | 56 | # enable, reload 57 | systemctl enable $1 58 | systemctl daemon-reload 59 | } 60 | -------------------------------------------------------------------------------- /xray.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | args=$@ 4 | is_sh_ver=v1.27 5 | 6 | . /etc/xray/sh/src/init.sh --------------------------------------------------------------------------------