From 4baa10ce06da178e90e31f1dcde0138237fdf81c Mon Sep 17 00:00:00 2001
From: SamNet-dev
Date: Tue, 24 Feb 2026 01:38:26 -0600
Subject: [PATCH] =?UTF-8?q?feat:=20migrate=20tunnelforge=20to=20Gitea=20?=
=?UTF-8?q?=E2=80=94=20update=20all=20URLs=20and=20self-update=20mechanism?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
LICENSE | 677 ++
README.md | 2677 ++++++
screenshots/dashboard.png | Bin 0 -> 73358 bytes
screenshots/tunnelforge-main.png | Bin 0 -> 103732 bytes
tunnelforge.sh | 10354 ++++++++++++++++++++++++
windows-client/tunnelforge-client.bat | 233 +
6 files changed, 13941 insertions(+)
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 screenshots/dashboard.png
create mode 100644 screenshots/tunnelforge-main.png
create mode 100644 tunnelforge.sh
create mode 100644 windows-client/tunnelforge-client.bat
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e336b82
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,677 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ TunnelForge — SSH Tunnel Manager
+ Copyright (C) 2026 SamNet Technologies, LLC
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4d7518f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2677 @@
+
+
+ ▀▀█▀▀ █ █ █▄ █ █▄ █ █▀▀ █ █▀▀ █▀█ █▀█ █▀▀ █▀▀
+ █ █ █ █ ▀█ █ ▀█ █▀▀ █ █▀ █ █ █▀█ █ █ █▀▀
+ █ ▀▀ █ █ █ █ ▀▀▀ ▀▀▀ █ ▀▀▀ █ █ ▀▀▀ ▀▀▀
+
+
+
+The Ultimate Single-File SSH Tunnel Manager
+
+
+
+
+
+
+
+
+
+
+ One script. Every tunnel type. Full TUI. Live dashboard.
+ SOCKS5 • Local Forward • Remote Forward • Jump Hosts • TLS Obfuscation • Telegram Bot • Kill Switch • DNS Leak Protection
+
+
+---
+
+## Quick Start
+
+**One-line install:**
+```bash
+curl -fsSL https://git.samnet.dev/SamNet-dev/tunnelforge/raw/branch/main/tunnelforge.sh -o tunnelforge.sh && sudo bash tunnelforge.sh install
+```
+
+**Or clone the repo:**
+```bash
+git clone https://git.samnet.dev/SamNet-dev/tunnelforge.git
+cd tunnelforge
+sudo bash tunnelforge.sh install
+```
+
+**Launch the interactive menu:**
+```bash
+tunnelforge menu
+```
+
+**Or use CLI directly:**
+```bash
+tunnelforge create # Create your first tunnel
+tunnelforge start my-tunnel # Start it
+tunnelforge dashboard # Watch it live
+```
+
+
+
+
+ Interactive TUI — manage tunnels, security, services, and more from a single menu
+
+
+---
+
+## Why TunnelForge?
+
+Most SSH tunnel tools are either too simple (just a wrapper around `ssh -D`) or too complex (requiring Docker, Go, Python, or a dozen config files). TunnelForge is different:
+
+| | TunnelForge | Others |
+|---|---|---|
+| **Installation** | Single bash file, zero dependencies | Python/Go/Node.js + package managers |
+| **Interface** | Full TUI menu + CLI + live dashboard | CLI-only or web UI requiring a browser |
+| **Security** | DNS leak protection, kill switch, audit scoring | Basic SSH only |
+| **Obfuscation** | TLS wrapping + PSK to bypass DPI/censorship | Not available |
+| **Monitoring** | Real-time sparkline bandwidth graphs | Log files |
+| **Notifications** | Telegram bot with remote commands | None |
+| **Persistence** | Auto-generated systemd services | Manual configuration |
+| **Education** | Built-in Learn menu with diagrams | External docs |
+| **Client Sharing** | One-click generated scripts (Linux + Windows) | Manual setup |
+
+**TunnelForge is the most complete SSH tunnel manager available as a single file.**
+
+---
+
+
+Features Overview
+
+### Tunnel Management
+- **SOCKS5 Dynamic Proxy** (`-D`) — Route all traffic through SSH server
+- **Local Port Forwarding** (`-L`) — Access remote services locally
+- **Remote/Reverse Forwarding** (`-R`) — Expose local services remotely
+- **Jump Host / Multi-Hop** (`-J`) — Chain through bastion servers
+- **AutoSSH Integration** — Automatic reconnection on drop
+- **ControlMaster Multiplexing** — Reuse SSH connections
+- **Multi-tunnel Support** — Run dozens of tunnels simultaneously
+
+### Security
+- **DNS Leak Protection** — Rewrites resolv.conf + locks with `chattr`
+- **Kill Switch** — iptables rules block all traffic if tunnel drops (IPv4 + IPv6)
+- **6-Point Security Audit** — Scored assessment of your tunnel security posture
+- **SSH Key Generation** — Create ed25519, RSA, or ECDSA keys
+- **SSH Key Deployment** — One-command deploy to remote servers
+- **Host Fingerprint Verification** — Verify server identity before connecting
+- **Server Hardening** — Automated sshd, firewall, fail2ban, sysctl configuration
+
+### Monitoring & Dashboard
+- **Live TUI Dashboard** — Real-time tunnel status with auto-refresh
+- **Sparkline Bandwidth Graphs** — ASCII sparklines (▁▂▃▄▅▆▇█) for RX/TX
+- **Traffic Counters** — Total bytes transferred per tunnel
+- **Uptime Tracking** — Per-tunnel uptime display
+- **Connection Quality** — Latency measurement with color-coded indicators
+- **Speed Test** — Built-in download speed test through tunnel
+- **Pagination** — Navigate across pages when running many tunnels
+
+### Telegram Bot
+- **Real-time Alerts** — Start, stop, fail, reconnect notifications
+- **Remote Commands** — `/tf_status`, `/tf_list`, `/tf_ip`, `/tf_config` and more
+- **Periodic Reports** — Scheduled status reports to your phone
+- **Client Sharing** — Send connection scripts + PSK via Telegram
+- **SOCKS5 Routing** — Bot works through your tunnel when Telegram is blocked
+
+### TLS Obfuscation (Anti-Censorship)
+- **Outbound TLS Wrapping** — SSH traffic disguised as HTTPS via stunnel
+- **Inbound PSK Protection** — SOCKS5 listener secured with Pre-Shared Key
+- **Client Script Generator** — Auto-generate connect scripts for Linux + Windows
+- **One-Click Server Setup** — Automated stunnel installation and configuration
+- **DPI Bypass** — Traffic appears as normal HTTPS on port 443
+
+### System Integration
+- **Systemd Service Generator** — Auto-create hardened unit files
+- **Backup & Restore** — Full configuration backup with rotation
+- **Server Setup Wizard** — Harden a fresh server for receiving tunnels
+- **Profile Management** — Create, edit, delete, import tunnel profiles
+- **Log Management** — Per-tunnel logs with rotation
+- **Clean Uninstall** — Complete removal of all files, services, and configs
+
+### Built-in Education
+- **Learn Menu** — 9 interactive lessons on SSH tunneling concepts
+- **Scenario Examples** — Step-by-step real-world use cases with diagrams
+- **ASCII Diagrams** — Visual traffic flow for every tunnel type
+
+
+
+---
+
+
+Tunnel Types Explained
+
+### SOCKS5 Dynamic Proxy (`-D`)
+
+Route **all** your TCP traffic through a remote SSH server. Your traffic appears to originate from the server's IP address.
+
+```
+┌──────────┐ ┌──────────┐ ┌──────────┐
+│ Client │ SSH │ SSH │ Direct │ Target │
+│ ├─────────►│ Server ├─────────►│ Website │
+│ :1080 │ Encrypted│ │ │ │
+└──────────┘ └──────────┘ └──────────┘
+ ▲
+ Browser
+ SOCKS5
+```
+
+**Use cases:** Private browsing, bypass geo-restrictions, hide your IP, route traffic through a different country.
+
+```bash
+tunnelforge create # Select "SOCKS5 Proxy" → set port 1080
+tunnelforge start my-proxy
+# Configure browser: SOCKS5 proxy → 127.0.0.1:1080
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+```
+
+---
+
+### Local Port Forwarding (`-L`)
+
+Access a **remote service** as if it were running locally. Map a local port to a service behind the SSH server.
+
+```
+┌──────────┐ ┌──────────┐ ┌──────────┐
+│ Client │ SSH │ SSH │ Local │ MySQL │
+│ ├─────────►│ Server ├─────────►│ :3306 │
+│ :3306 │ Encrypted│ │ Network │ │
+└──────────┘ └──────────┘ └──────────┘
+ ▲
+ mysql -h
+ 127.0.0.1
+```
+
+**Use cases:** Access remote databases, internal web apps, admin panels behind firewalls.
+
+```bash
+tunnelforge create # Select "Local Forward" → local 3306 → remote db:3306
+tunnelforge start db-tunnel
+mysql -h 127.0.0.1 -P 3306 -u admin -p
+```
+
+---
+
+### Remote/Reverse Forwarding (`-R`)
+
+Expose a **local service** to the outside world through a remote SSH server. Users connect to the server and reach your local machine.
+
+```
+┌──────────┐ ┌──────────┐ ┌──────────┐
+│ Local │ SSH │ SSH │ Public │ Users │
+│ Dev App │◄────────►│ Server │◄─────────│ on Web │
+│ :3000 │ Encrypted│ :9090 │ │ │
+└──────────┘ └──────────┘ └──────────┘
+```
+
+**Use cases:** Webhook development, share local app for testing, NAT traversal, demo to clients.
+
+```bash
+tunnelforge create # Select "Remote Forward" → remote 9090 ← local 3000
+tunnelforge start dev-share
+# Others access: http://your-server:9090
+```
+
+---
+
+### Jump Hosts / Multi-Hop (`-J`)
+
+Reach servers behind **multiple layers** of firewalls by chaining through intermediate SSH servers.
+
+```
+┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
+│ Client │────►│ Bastion │────►│ Jump 2 │────►│ Target │
+│ │ SSH │ Server │ SSH │ Server │ SSH │ Server │
+└──────────┘ └──────────┘ └──────────┘ └──────────┘
+```
+
+**Use cases:** Corporate networks, multi-tier architectures, isolated environments, high-security zones.
+
+```bash
+tunnelforge create # Select "Jump Host" → jumps: admin@bastion:22
+tunnelforge start corp-tunnel
+```
+
+
+
+---
+
+
+Installation
+
+### Requirements
+
+| Requirement | Details |
+|---|---|
+| **OS** | Linux (Ubuntu, Debian, CentOS, Fedora, Arch, Alpine) |
+| **Bash** | 4.3 or higher |
+| **Privileges** | Root access for installation |
+| **SSH** | OpenSSH client (pre-installed on most systems) |
+| **Optional** | `autossh` (auto-reconnect), `stunnel` (TLS obfuscation), `sshpass` (password auth) |
+
+### Install
+
+```bash
+# Option 1: Git clone
+git clone https://git.samnet.dev/SamNet-dev/tunnelforge.git
+cd tunnelforge
+sudo bash tunnelforge.sh install
+
+# Option 2: Direct download
+curl -fsSL https://git.samnet.dev/SamNet-dev/tunnelforge/raw/branch/main/tunnelforge.sh -o tunnelforge.sh
+sudo bash tunnelforge.sh install
+```
+
+### Verify Installation
+
+```bash
+tunnelforge version
+# TunnelForge v1.0.0
+```
+
+### Directory Structure
+
+After installation, TunnelForge creates:
+
+```
+/opt/tunnelforge/
+├── tunnelforge.sh # Main script
+├── config/
+│ └── tunnelforge.conf # Global configuration
+├── profiles/
+│ └── *.conf # Tunnel profiles
+├── pids/ # Running tunnel PIDs
+├── logs/ # Per-tunnel log files
+├── backups/ # Configuration backups
+├── data/
+│ ├── bandwidth/ # Bandwidth history (sparklines)
+│ └── reconnects/ # Reconnect statistics
+└── sockets/ # SSH ControlMaster sockets
+```
+
+A symlink is created at `/usr/local/bin/tunnelforge` for global access.
+
+
+
+---
+
+
+Quick Examples
+
+### Browse Privately via SOCKS5
+
+```bash
+tunnelforge create
+# → Name: private-proxy
+# → Type: SOCKS5
+# → Server: user@myserver.com
+# → Port: 1080
+
+tunnelforge start private-proxy
+
+# Test it
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+
+# Configure Firefox: Settings → Network → Manual Proxy → SOCKS5: 127.0.0.1:1080
+```
+
+### Access a Remote Database
+
+```bash
+tunnelforge create
+# → Name: prod-db
+# → Type: Local Forward
+# → Server: admin@db-server.internal
+# → Local port: 3306 → Remote: localhost:3306
+
+tunnelforge start prod-db
+mysql -h 127.0.0.1 -P 3306 -u dbuser -p
+```
+
+### Share Your Local Dev Server
+
+```bash
+tunnelforge create
+# → Name: demo-share
+# → Type: Remote Forward
+# → Server: user@public-vps.com
+# → Remote port: 8080 ← Local: localhost:3000
+
+tunnelforge start demo-share
+# Share with anyone: http://public-vps.com:8080
+```
+
+### Chain Through Jump Hosts
+
+```bash
+tunnelforge create
+# → Name: corp-access
+# → Type: Jump Host
+# → Jump: admin@bastion.corp.com:22
+# → Target: user@internal-server:22
+# → SOCKS5 port: 1080
+
+tunnelforge start corp-access
+```
+
+### Bypass Censorship with TLS Obfuscation
+
+```bash
+# First, set up stunnel on your VPS
+tunnelforge obfs-setup my-tunnel
+
+# Now SSH traffic is wrapped in TLS on port 443
+# DPI sees: normal HTTPS traffic
+# Reality: SSH tunnel inside TLS
+tunnelforge start my-tunnel
+
+# Share with others
+tunnelforge client-script my-tunnel # Generates connect scripts
+tunnelforge telegram share my-tunnel # Send scripts via Telegram
+```
+
+
+
+---
+
+
+CLI Reference
+
+### Tunnel Commands
+
+| Command | Description |
+|---|---|
+| `tunnelforge start ` | Start a tunnel |
+| `tunnelforge stop ` | Stop a tunnel |
+| `tunnelforge restart ` | Restart a tunnel |
+| `tunnelforge start-all` | Start all autostart tunnels |
+| `tunnelforge stop-all` | Stop all running tunnels |
+| `tunnelforge status` | Show all tunnel statuses |
+| `tunnelforge dashboard` | Launch live TUI dashboard |
+| `tunnelforge logs [name]` | Tail tunnel logs |
+
+### Profile Commands
+
+| Command | Description |
+|---|---|
+| `tunnelforge create` | Create a new tunnel profile (wizard) |
+| `tunnelforge list` | List all profiles |
+| `tunnelforge delete ` | Delete a profile |
+
+### Security Commands
+
+| Command | Description |
+|---|---|
+| `tunnelforge audit` | Run 6-point security audit |
+| `tunnelforge key-gen [type]` | Generate SSH key (ed25519/rsa/ecdsa) |
+| `tunnelforge key-deploy ` | Deploy SSH key to server |
+| `tunnelforge fingerprint [port]` | Verify SSH host fingerprint |
+
+### Telegram Commands
+
+| Command | Description |
+|---|---|
+| `tunnelforge telegram setup` | Configure Telegram bot |
+| `tunnelforge telegram test` | Send test notification |
+| `tunnelforge telegram status` | Show notification config |
+| `tunnelforge telegram send ` | Send a message |
+| `tunnelforge telegram report` | Send status report |
+| `tunnelforge telegram share [name]` | Share client scripts via Telegram |
+
+### Service Commands
+
+| Command | Description |
+|---|---|
+| `tunnelforge service ` | Generate systemd service |
+| `tunnelforge service enable` | Enable and start service |
+| `tunnelforge service disable` | Disable and stop service |
+| `tunnelforge service status` | Show service status |
+| `tunnelforge service remove` | Remove service file |
+
+### System Commands
+
+| Command | Description |
+|---|---|
+| `tunnelforge menu` | Launch interactive TUI |
+| `tunnelforge install` | Install TunnelForge |
+| `tunnelforge server-setup` | Harden server for tunnels |
+| `tunnelforge obfs-setup ` | Set up TLS obfuscation |
+| `tunnelforge client-config ` | Show client connection config |
+| `tunnelforge client-script ` | Generate client scripts |
+| `tunnelforge backup` | Backup all configs |
+| `tunnelforge restore [file]` | Restore from backup |
+| `tunnelforge uninstall` | Remove everything |
+| `tunnelforge version` | Show version |
+| `tunnelforge help` | Show help |
+
+
+
+---
+
+
+Interactive TUI Menu
+
+Launch with `tunnelforge menu` or just `tunnelforge` (no arguments):
+
+```
+╔══════════════════════════════════════════════════════════════╗
+║ TunnelForge — Main Menu ║
+╚══════════════════════════════════════════════════════════════╝
+
+ ── Tunnels ──
+ 1) Create new tunnel Setup wizard
+ 2) Start a tunnel Launch SSH tunnel
+ 3) Stop a tunnel Terminate tunnel
+ 4) Start All tunnels Launch autostart tunnels
+ 5) Stop All tunnels Terminate all
+
+ ── Monitoring ──
+ 6) Status Show tunnel statuses
+ 7) Dashboard Live TUI dashboard
+
+ ── Management ──
+ 8) Profiles Manage tunnel profiles
+ 9) Settings Configure defaults
+ s) Services Systemd service manager
+ b) Backup / Restore Manage backups
+
+ ── Security ──
+ x) Security Audit Check security posture
+ k) SSH Key Management Generate & deploy keys
+ f) Fingerprint Check Verify host fingerprints
+
+ ── Extras ──
+ t) Telegram Notification settings
+ c) Client Configs TLS+PSK connection info
+ e) Examples Real-world scenarios
+ l) Learn SSH tunnel concepts
+ a) About Version & info
+
+ u) Uninstall
+ q) Quit
+
+ Select:
+```
+
+Navigate by pressing a single key. No Enter needed. Every menu is keyboard-driven.
+
+
+
+---
+
+
+Live Dashboard
+
+Launch with `tunnelforge dashboard` or press `7` in the main menu:
+
+
+
+
+ Live dashboard with sparkline bandwidth graphs, active connections, reconnect log, and system resources
+
+
+```
+╔══════════════════════════════════════════════════════════════╗
+║ TunnelForge Dashboard v1.0.0 ║
+║ Page 1/2 │ 2026-02-07 14:32:15 ║
+╚══════════════════════════════════════════════════════════════╝
+
+ NAME TYPE STATUS LOCAL UPTIME
+ ────────────────────────────────────────────────────────────
+ iran-proxy SOCKS5 ● ALIVE 127.0.0.1:1080 2h 8m
+ RX ▁▂▃▅▇█▇▅▃▂ 412.3 MB TX ▁▁▂▃▅▇▅▃ 82.1 MB
+
+ t1-socks5 SOCKS5 ● ALIVE 127.0.0.1:4001 2h 9m
+ RX ▁▁▁▂▂▃▂▁▁▁ 96.7 KB TX ▁▁▁▁▂▂▁▁ 12.3 KB
+
+ db-tunnel LOCAL ■ STOPPED 127.0.0.1:3306 —
+
+ dev-share REMOTE ● ALIVE 0.0.0.0:9090 45m
+ RX ▁▂▂▃▃▂▁▁▁▁ 1.2 MB TX ▁▁▁▂▃▅▃▂ 890 KB
+
+ ── Active Connections ──
+ iran-proxy : 3 connections
+ t1-socks5 : 1 connection
+
+ ── Recent Log ──
+ 14:32:10 [info] Tunnel 'iran-proxy' reconnected (AutoSSH)
+ 14:30:05 [info] Speed test: 12.4 Mbps via iran-proxy
+
+ s=start t=stop r=restart c=create p=speed g=qlty q=quit [>]
+```
+
+### Dashboard Keyboard Controls
+
+| Key | Action |
+|---|---|
+| `s` | Start a tunnel |
+| `t` | Stop a tunnel |
+| `r` | Restart all running tunnels |
+| `c` | Create a new profile |
+| `p` | Run speed test |
+| `g` | Check connection quality |
+| `[` / `]` | Previous / next page |
+| `q` | Exit dashboard |
+
+### What It Shows
+- **Status** — Live running/stopped state per tunnel
+- **Uptime** — How long each tunnel has been connected
+- **Sparkline Graphs** — Real-time bandwidth visualization using 8 levels (▁▂▃▄▅▆▇█)
+- **Traffic Totals** — Cumulative RX/TX bytes per tunnel
+- **Active Connections** — Number of established TCP connections through each tunnel
+- **Recent Logs** — Last 4 log entries across all tunnels
+- **Pagination** — Automatically pages when running 5+ tunnels
+
+
+
+---
+
+
+Security Features
+
+### DNS Leak Protection
+
+Prevents DNS queries from bypassing the tunnel and revealing your real location.
+
+**How it works:**
+1. Backs up your current `/etc/resolv.conf`
+2. Rewrites it to use only tunnel-safe DNS servers (default: 8.8.8.8, 8.8.4.4)
+3. Locks the file with `chattr +i` (immutable) to prevent system overrides
+4. Automatically restores original DNS when tunnel stops
+
+```bash
+# Enable per-profile in the wizard or editor
+# Verify with:
+tunnelforge audit # Check DNS leak protection status
+```
+
+### Kill Switch
+
+If the tunnel drops, **all internet traffic is blocked** to prevent data leaks.
+
+**How it works:**
+1. Creates a custom `TUNNELFORGE` iptables chain
+2. Allows only SSH tunnel traffic + loopback
+3. Blocks everything else (IPv4 + IPv6)
+4. Automatically removes rules when tunnel stops or is manually disabled
+
+```bash
+# Enable per-profile in the wizard or editor
+# Verify with:
+tunnelforge audit # Check kill switch status
+```
+
+### SSH Key Management
+
+```bash
+# Generate a new key
+tunnelforge key-gen ed25519 # Recommended (fast, secure)
+tunnelforge key-gen rsa # 4096-bit RSA (broad compatibility)
+tunnelforge key-gen ecdsa # ECDSA alternative
+
+# Deploy to a tunnel's server
+tunnelforge key-deploy my-tunnel
+```
+
+### Host Fingerprint Verification
+
+Verify a server's SSH fingerprint before trusting it:
+
+```bash
+tunnelforge fingerprint myserver.com 22
+# Displays SHA256 and MD5 fingerprints
+# Compare against your server's known fingerprint
+```
+
+### 6-Point Security Audit
+
+Scores your security posture out of 100 points:
+
+```bash
+tunnelforge audit
+```
+
+| Check | What It Verifies |
+|---|---|
+| SSH Key Permissions | Private keys are 600 or 400 |
+| SSH Directory | `~/.ssh` is 700 |
+| DNS Leak Protection | Active DNS protection on running tunnels |
+| Kill Switch | iptables chain is active |
+| Tunnel Integrity | PIDs are valid, processes running |
+| System Packages | Required security tools installed |
+
+### Server Hardening
+
+Prepare a fresh server to receive SSH tunnels securely:
+
+```bash
+tunnelforge server-setup
+```
+
+**What it configures:**
+- **SSH daemon** — Disable password auth, disable root login, custom port
+- **Firewall** — UFW/iptables rules for SSH + tunnel ports only
+- **Fail2ban** — Auto-ban after failed login attempts
+- **Kernel** — Sysctl hardening (SYN flood protection, ICMP redirects, IP forwarding)
+
+
+
+---
+
+
+TLS Obfuscation (Anti-Censorship)
+
+In networks with Deep Packet Inspection (DPI), SSH traffic can be detected and blocked. TunnelForge wraps your SSH connection inside a TLS layer, making it look like normal HTTPS traffic.
+
+### How It Works
+
+```
+Without TLS Obfuscation:
+Client ──── SSH (detectable) ────► VPS ← DPI can block this
+
+With TLS Obfuscation:
+Client ──── TLS/443 (looks like HTTPS) ────► VPS ──── SSH ────► Internet
+ ▲
+ stunnel
+ unwraps TLS
+```
+
+### Setup (Server Side)
+
+```bash
+# Automatically installs stunnel, generates TLS cert, configures port mapping
+tunnelforge obfs-setup my-tunnel
+```
+
+This will:
+1. Install `stunnel` on the remote server
+2. Generate a self-signed TLS certificate
+3. Map port 443 (TLS) → port 22 (SSH)
+4. Enable as a systemd service
+5. Open the firewall port
+
+### Inbound PSK Protection
+
+Protect your local SOCKS5 listener with a Pre-Shared Key. Without the PSK, nobody can connect to your tunnel — even if they find the port.
+
+```
+Client with PSK ──── TLS+PSK ────► Your Machine ──── SOCKS5 ────► Tunnel
+Unauthorized ──── TLS ────► Your Machine ──── REJECTED
+```
+
+### Share With Others
+
+Generate standalone connect scripts that anyone can use:
+
+```bash
+# Generate Linux + Windows scripts
+tunnelforge client-script my-tunnel
+
+# Share via Telegram (sends scripts + PSK + instructions)
+tunnelforge telegram share my-tunnel
+```
+
+**Generated scripts include:**
+- `tunnelforge-connect.sh` — Linux bash script (`./connect.sh start|stop|status`)
+- `tunnelforge-connect.ps1` — Windows PowerShell script
+
+Both scripts auto-configure stunnel, create PSK files, and manage the connection lifecycle.
+
+### Standalone Windows Client
+
+TunnelForge also ships with **[`windows-client/tunnelforge-client.bat`](windows-client/tunnelforge-client.bat)** — a ready-to-distribute Windows batch client. Users just double-click it, paste their connection details, and they're connected. No PowerShell required.
+
+**Features:**
+- Interactive setup — prompts for server, port, and PSK
+- Auto-installs stunnel (via winget, Chocolatey, or manual download link)
+- Saves connection for instant reconnect
+- Commands: `tunnelforge-client.bat stop` / `status`
+- Prints browser proxy setup instructions (Firefox + Chrome)
+
+```
+How to distribute:
+1. Send windows-client/tunnelforge-client.bat to the user
+2. Give them the PSK + server info (from: tunnelforge client-config )
+3. User double-clicks the .bat → enters details → connected
+```
+
+
+
+---
+
+
+Telegram Bot
+
+Get real-time tunnel notifications on your phone and control tunnels remotely.
+
+### Setup
+
+```bash
+tunnelforge telegram setup
+```
+
+1. **Create a bot** — Talk to [@BotFather](https://t.me/BotFather) on Telegram, send `/newbot`
+2. **Enter your token** — Paste the bot token into TunnelForge
+3. **Get your Chat ID** — Send `/start` to your bot, TunnelForge auto-detects your ID
+4. **Done** — You'll receive a test message confirming setup
+
+### Notifications You'll Receive
+
+| Event | Message |
+|---|---|
+| Tunnel started | Profile name, PID, tunnel type |
+| Tunnel stopped | Profile name |
+| Tunnel failed | Error details |
+| Tunnel reconnected | AutoSSH auto-recovery |
+| Security alert | DNS leak or kill switch event |
+| Status report | All tunnels overview (periodic) |
+
+### Bot Commands
+
+Send these commands to your bot from Telegram:
+
+| Command | Response |
+|---|---|
+| `/tf_status` | All tunnel statuses |
+| `/tf_list` | List all profiles |
+| `/tf_ip` | Server's public IP |
+| `/tf_config` | Client connection configs (PSK info) |
+| `/tf_uptime` | Server uptime |
+| `/tf_report` | Full status report |
+| `/tf_help` | Available commands |
+
+### Configuration
+
+```bash
+tunnelforge telegram status # View current config
+tunnelforge telegram test # Send test message
+tunnelforge telegram send "Hello from TunnelForge!"
+```
+
+Enable periodic reports (e.g., every hour):
+```
+Settings → Telegram → Toggle Status Reports → Set Interval
+```
+
+
+
+---
+
+
+Systemd Services
+
+Make your tunnels survive reboots with auto-generated systemd service files.
+
+### Usage
+
+```bash
+# Generate a service file
+tunnelforge service my-tunnel
+
+# Enable and start (survives reboot)
+tunnelforge service my-tunnel enable
+
+# Check status
+tunnelforge service my-tunnel status
+
+# Disable
+tunnelforge service my-tunnel disable
+
+# Remove service file
+tunnelforge service my-tunnel remove
+```
+
+### Generated Service Features
+
+The auto-generated unit file includes security hardening:
+
+- `ProtectSystem=strict` — Read-only filesystem
+- `ProtectHome=tmpfs` — Isolated home directory
+- `PrivateTmp=true` — Private temp directory
+- `CAP_NET_ADMIN` — Only if kill switch is enabled
+- `CAP_LINUX_IMMUTABLE` — Only if DNS leak protection is enabled
+- Automatic restart policies
+- Proper start/stop timeouts
+
+
+
+---
+
+
+Backup & Restore
+
+### Backup
+
+```bash
+tunnelforge backup
+```
+
+Creates a timestamped `.tar.gz` archive containing:
+- All tunnel profiles
+- Global configuration
+- SSH keys (if stored in TunnelForge directory)
+- Systemd service files
+
+Backups are stored in `/opt/tunnelforge/backups/` with automatic rotation.
+
+### Restore
+
+```bash
+# Restore from latest backup
+tunnelforge restore
+
+# Restore from specific file
+tunnelforge restore /path/to/backup.tar.gz
+```
+
+
+
+---
+
+
+Configuration Reference
+
+### Global Config (`/opt/tunnelforge/config/tunnelforge.conf`)
+
+| Setting | Default | Description |
+|---|---|---|
+| `SSH_DEFAULT_USER` | `root` | Default SSH username |
+| `SSH_DEFAULT_PORT` | `22` | Default SSH port |
+| `SSH_DEFAULT_KEY` | — | Default identity key path |
+| `SSH_CONNECT_TIMEOUT` | `10` | Connection timeout (seconds) |
+| `AUTOSSH_ENABLED` | `true` | Enable AutoSSH by default |
+| `AUTOSSH_POLL` | `30` | AutoSSH poll interval (seconds) |
+| `CONTROLMASTER_ENABLED` | `false` | SSH connection multiplexing |
+| `LOG_LEVEL` | `info` | Logging verbosity (debug/info/warn/error) |
+| `DASHBOARD_REFRESH` | `3` | Dashboard refresh rate (seconds) |
+| `DNS_LEAK_PROTECTION` | `false` | DNS leak protection default |
+| `KILL_SWITCH` | `false` | Kill switch default |
+| `TELEGRAM_ENABLED` | `false` | Enable Telegram notifications |
+| `TELEGRAM_BOT_TOKEN` | — | Bot token from @BotFather |
+| `TELEGRAM_CHAT_ID` | — | Your Telegram chat ID |
+| `TELEGRAM_ALERTS` | `true` | Send tunnel event alerts |
+| `TELEGRAM_PERIODIC_STATUS` | `false` | Send periodic reports |
+| `TELEGRAM_STATUS_INTERVAL` | `3600` | Report interval (seconds) |
+
+### Profile Fields
+
+Each tunnel profile (`/opt/tunnelforge/profiles/.conf`) contains:
+
+| Field | Description |
+|---|---|
+| `TUNNEL_TYPE` | `socks5`, `local`, `remote`, or `jump` |
+| `SSH_HOST` | Server hostname or IP |
+| `SSH_PORT` | SSH port (default 22) |
+| `SSH_USER` | SSH username |
+| `SSH_PASSWORD` | SSH password (optional) |
+| `IDENTITY_KEY` | Path to SSH private key |
+| `LOCAL_BIND_ADDR` | Local bind address |
+| `LOCAL_PORT` | Local port number |
+| `REMOTE_HOST` | Remote target host |
+| `REMOTE_PORT` | Remote target port |
+| `JUMP_HOSTS` | Comma-separated jump hosts |
+| `SSH_OPTIONS` | Extra SSH flags |
+| `AUTOSSH_ENABLED` | AutoSSH toggle |
+| `DNS_LEAK_PROTECTION` | DNS protection toggle |
+| `KILL_SWITCH` | Kill switch toggle |
+| `AUTOSTART` | Start on boot |
+| `OBFS_MODE` | `none` or `stunnel` |
+| `OBFS_PORT` | TLS obfuscation port |
+| `OBFS_LOCAL_PORT` | Inbound TLS+PSK port |
+| `OBFS_PSK` | Pre-Shared Key (hex) |
+| `DESCRIPTION` | Profile description |
+
+
+
+---
+
+
+Real-World Scenarios
+
+Each scenario below is expandable and shows the **exact wizard steps** you'll follow. Both SSH-only and TLS-encrypted variants are covered where applicable.
+
+
+Scenario 1: Private Browsing via SOCKS5
+
+**Goal:** Route all your browser traffic through a VPS so websites see the VPS IP instead of yours.
+
+```
+Your PC :1080 ──── SSH (Encrypted) ────► VPS ──── Direct ────► Internet
+ ▲
+ Websites see
+ the VPS IP
+```
+
+**What you need:** A VPS or remote server with SSH access.
+
+#### Wizard Steps (SSH-only)
+
+```
+tunnelforge create
+```
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 1 | Profile name | `private-proxy` |
+| 2 | Tunnel type | `1` — SOCKS5 Proxy |
+| 3 | SSH host | Your VPS IP (e.g. `45.33.32.10`) |
+| 4 | SSH port | `22` (default) |
+| 5 | SSH user | `root` (or your username) |
+| 6 | SSH password | Your password (or Enter to skip for key auth) |
+| 7 | Identity key | `~/.ssh/id_ed25519` (or Enter to skip) |
+| 8 | Auth test | Automatic — verifies connection |
+| 9a | Bind address | `127.0.0.1` (local only) or `0.0.0.0` (share with LAN) |
+| 9b | SOCKS5 port | `1080` |
+| 10 | Connection mode | `1` — Regular SSH |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` (recommended) |
+| 13 | Save & start | `y` then `y` |
+
+#### Wizard Steps (TLS-encrypted — for censored networks)
+
+Same as above, but at step 10:
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 10 | Connection mode | `2` — TLS Encrypted |
+| 10a | TLS port | `443` (looks like HTTPS) |
+| 10b | Setup stunnel now? | `y` (auto-installs on server) |
+| 11 | Inbound protection | `1` — None (you're the only user) |
+
+#### After Starting
+
+**Firefox:**
+1. Settings → search "proxy" → Manual proxy configuration
+2. SOCKS Host: `127.0.0.1` — Port: `1080`
+3. Select "SOCKS v5"
+4. Check "Proxy DNS when using SOCKS v5"
+
+**Chrome:**
+```bash
+google-chrome --proxy-server="socks5://127.0.0.1:1080"
+```
+
+**Test it works:**
+```bash
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+# Should show your VPS IP, not your real IP
+```
+
+
+
+
+Scenario 2: Access a Remote Database
+
+**Goal:** Access MySQL/PostgreSQL running on your VPS as if it were on your local machine.
+
+```
+Your PC :3306 ──── SSH (Encrypted) ────► VPS ──── Local ────► MySQL :3306
+```
+
+**What you need:** A VPS with a database running (e.g. MySQL on port 3306).
+
+#### Wizard Steps
+
+```
+tunnelforge create
+```
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 1 | Profile name | `prod-db` |
+| 2 | Tunnel type | `2` — Local Port Forward |
+| 3 | SSH host | Your VPS IP (e.g. `45.33.32.10`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `root` |
+| 6 | SSH password | Your password (or Enter to skip) |
+| 7 | Identity key | Enter to skip (or path to key) |
+| 8 | Auth test | Automatic |
+| 9a | Bind address | `127.0.0.1` |
+| 9b | Local port | `3306` (port on YOUR machine) |
+| 9c | Remote host | `127.0.0.1` (means "on the VPS itself") |
+| 9d | Remote port | `3306` (MySQL port on VPS) |
+| 10 | Connection mode | `1` — Regular SSH |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` then `y` |
+
+#### After Starting
+
+```bash
+# MySQL
+mysql -h 127.0.0.1 -P 3306 -u dbuser -p
+
+# PostgreSQL (change ports to 5432)
+psql -h 127.0.0.1 -p 5432 -U postgres
+
+# Redis (change ports to 6379)
+redis-cli -h 127.0.0.1 -p 6379
+
+# Web admin panel (change ports to 8080)
+# Open browser: http://127.0.0.1:8080
+```
+
+#### Common Variations
+
+| Service | Local Port | Remote Port |
+|---|---|---|
+| MySQL | 3306 | 3306 |
+| PostgreSQL | 5432 | 5432 |
+| Redis | 6379 | 6379 |
+| Web panel | 8080 | 8080 |
+| MongoDB | 27017 | 27017 |
+
+> **Tip:** Set Remote host to another IP on the VPS network (e.g. `10.0.0.5`) to reach a database on a private subnet that only the VPS can access.
+
+
+
+
+Scenario 3: Share Your Local Dev Server
+
+**Goal:** You have a website running locally (e.g. on port 3000) and want others on the internet to access it through your VPS.
+
+```
+Local App :3000 ◄──── SSH (Encrypted) ────► VPS :9090 ◄──── Users on Web
+```
+
+**What you need:** A local service running + a VPS with a public IP.
+
+#### Wizard Steps
+
+```
+tunnelforge create
+```
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 1 | Profile name | `dev-share` |
+| 2 | Tunnel type | `3` — Remote/Reverse Forward |
+| 3 | SSH host | Your VPS IP (e.g. `45.33.32.10`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `root` |
+| 6 | SSH password | Your password |
+| 7 | Identity key | Enter to skip |
+| 8 | Auth test | Automatic |
+| 9a | Remote bind | `0.0.0.0` (public access — requires `GatewayPorts yes` in sshd) |
+| 9b | Remote port | `9090` (port on VPS others connect to) |
+| 9c | Local host | `127.0.0.1` (this machine) |
+| 9d | Local port | `3000` (your running app) |
+| 10 | Connection mode | `1` — Regular SSH |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` then `y` |
+
+#### Important: Enable GatewayPorts
+
+If using `0.0.0.0` bind (public access), your VPS sshd needs:
+
+```bash
+# On VPS: edit /etc/ssh/sshd_config
+GatewayPorts yes
+
+# Then restart sshd
+sudo systemctl restart sshd
+```
+
+If using `127.0.0.1` bind, the port is only accessible from the VPS itself.
+
+#### After Starting
+
+```bash
+# Make sure your local service is running first:
+python3 -m http.server 3000 # or: npm start, etc.
+
+# Test from VPS (SSH into it):
+curl http://localhost:9090
+
+# Test from anywhere (if bind is 0.0.0.0):
+curl http://45.33.32.10:9090
+
+# Share with clients:
+# "Visit http://45.33.32.10:9090 to see the demo"
+```
+
+#### Common Use Cases
+
+| Use Case | Local Port | What's Exposed |
+|---|---|---|
+| Node.js dev server | 3000 | Web app |
+| React/Vue dev server | 5173 | Frontend |
+| Webhook receiver | 8080 | API endpoint |
+| SSH to home PC | 22 | SSH access |
+
+
+
+
+Scenario 4: Multi-Hop Through Bastion / Jump Hosts
+
+**Goal:** Reach a server that is NOT directly accessible from the internet. You hop through one or more intermediate servers.
+
+```
+Your PC ── SSH ──► Bastion (public) ── SSH ──► Target (hidden)
+```
+
+**What you need:** SSH access to the jump/bastion server + the target server.
+
+#### Wizard Steps (SOCKS5 at target)
+
+```
+tunnelforge create
+```
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 1 | Profile name | `corp-access` |
+| 2 | Tunnel type | `4` — Jump Host |
+| 3 | SSH host | **Target** IP (e.g. `10.0.50.100`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `admin` (user on **target**) |
+| 6 | SSH password | Password for **target** |
+| 7 | Identity key | Key for **target** |
+| 8 | Auth test | May fail (target not reachable directly) — continue anyway |
+| 9a | Jump hosts | `root@bastion.example.com:22` |
+| 9b | Tunnel type at destination | `1` — SOCKS5 Proxy |
+| 9c | Bind address | `127.0.0.1` |
+| 9d | SOCKS5 port | `1080` |
+| 10 | Connection mode | `1` — Regular SSH |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` then `y` |
+
+> **Important:** Step 3-7 are for the **TARGET** server. Jump host credentials go in step 9a using the format `user@host:port`.
+
+#### Wizard Steps (Local Forward at target)
+
+Same as above, but at step 9:
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 9a | Jump hosts | `root@bastion.example.com:22` |
+| 9b | Tunnel type at destination | `2` — Local Port Forward |
+| 9c | Bind address | `127.0.0.1` |
+| 9d | Local port | `8080` |
+| 9e | Remote host | `127.0.0.1` (on the target) |
+| 9f | Remote port | `80` (web server on target) |
+
+#### Multiple Jump Hosts
+
+Chain through several servers by comma-separating them:
+
+```
+Jump hosts: user1@hop1.com:22,user2@hop2.com:22
+```
+
+```
+Your PC ──► hop1.com ──► hop2.com ──► Target
+```
+
+#### After Starting
+
+```bash
+# SOCKS5 mode — set browser proxy:
+# 127.0.0.1:1080
+
+# Local Forward mode — open in browser:
+# http://127.0.0.1:8080 → shows target's web server
+```
+
+
+
+
+Scenario 5: Bypass DPI Censorship (Single VPS)
+
+**Goal:** Your ISP uses Deep Packet Inspection (DPI) to detect and block SSH traffic. Wrap SSH in TLS so it looks like normal HTTPS.
+
+```
+Without TLS: Your PC ──── SSH (blocked by DPI) ────► VPS
+With TLS: Your PC ──── TLS/443 (looks like HTTPS) ────► VPS ──► Internet
+```
+
+**What you need:** 1 VPS outside the censored network.
+
+#### Wizard Steps
+
+```
+tunnelforge create
+```
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 1 | Profile name | `bypass-proxy` |
+| 2 | Tunnel type | `1` — SOCKS5 Proxy |
+| 3 | SSH host | Your VPS IP (e.g. `45.33.32.10`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `root` |
+| 6 | SSH password | Your password |
+| 7 | Identity key | Enter to skip |
+| 8 | Auth test | Automatic |
+| 9a | Bind address | `127.0.0.1` |
+| 9b | SOCKS5 port | `1080` |
+| **10** | **Connection mode** | **`2` — TLS Encrypted** |
+| 10a | TLS port | `443` (mimics HTTPS — most effective) |
+| 10b | Setup stunnel on server? | `y` (auto-installs stunnel on VPS) |
+| 11 | Inbound protection | `1` — None (you're connecting directly) |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` then `y` |
+
+#### What Happens Behind the Scenes
+
+1. TunnelForge installs `stunnel` on your VPS
+2. Stunnel listens on port 443 (TLS) and forwards to SSH port 22
+3. Your local SSH client connects through stunnel via `openssl s_client`
+4. DPI only sees a TLS handshake on port 443 — indistinguishable from HTTPS
+
+#### After Starting
+
+```bash
+# Set browser SOCKS5 proxy: 127.0.0.1:1080
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+# Shows VPS IP — you're browsing through TLS-wrapped SSH
+```
+
+#### What DPI Sees
+
+```
+Your PC ──── HTTPS traffic on port 443 ────► VPS IP
+Verdict: Normal website browsing. Allowed.
+```
+
+
+
+
+Scenario 6: Double-Hop TLS Chain (Two VPS)
+
+**Goal:** Run a shared proxy for multiple users. VPS-A is the entry point (relay). VPS-B is the exit point. Both legs are TLS-encrypted. Users connect with a PSK.
+
+```
+Users ── TLS+PSK:1443 ──► VPS-A (relay) ── TLS:443 ──► VPS-B (exit) ──► Internet
+ stunnel+PSK stunnel
+ SOCKS5:1080 SSH:22
+```
+
+**What you need:** 2 VPS servers. VPS-A = relay (can be in censored country). VPS-B = exit (outside).
+
+#### Wizard Steps (run on VPS-A)
+
+Install TunnelForge on VPS-A, then:
+
+```
+tunnelforge create
+```
+
+| Step | Prompt | What to enter |
+|---|---|---|
+| 1 | Profile name | `double-hop` |
+| 2 | Tunnel type | `1` — SOCKS5 Proxy |
+| 3 | SSH host | **VPS-B** IP (e.g. `203.0.113.50`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `root` |
+| 6 | SSH password | VPS-B password |
+| 7 | Identity key | Enter to skip |
+| 8 | Auth test | Automatic |
+| 9a | Bind address | `127.0.0.1` (stunnel handles external) |
+| 9b | SOCKS5 port | `1080` |
+| **10** | **Connection mode** | **`2` — TLS Encrypted** |
+| 10a | TLS port | `443` |
+| 10b | Setup stunnel on VPS-B? | `y` |
+| **11** | **Inbound protection** | **`2` — TLS + PSK** |
+| 11a | Inbound TLS port | `1443` (users connect here) |
+| 11b | PSK | Auto-generated (saved in profile) |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` then `y` |
+
+#### Generate Client Scripts for Users
+
+```bash
+# On VPS-A after tunnel is running:
+tunnelforge client-script double-hop
+
+# Creates:
+# tunnelforge-connect.sh (Linux)
+# tunnelforge-connect.ps1 (Windows)
+
+# Or send via Telegram:
+tunnelforge telegram share double-hop
+```
+
+#### What Users Do
+
+**Linux:**
+```bash
+chmod +x tunnelforge-connect.sh
+./tunnelforge-connect.sh # Connect
+./tunnelforge-connect.sh stop # Disconnect
+./tunnelforge-connect.sh status # Check
+# Set browser proxy: 127.0.0.1:1080
+```
+
+**Windows PowerShell:**
+```powershell
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 # Connect
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 stop # Disconnect
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 status # Check
+# Set browser proxy: 127.0.0.1:1080
+```
+
+**Windows Batch (standalone client):**
+```
+tunnelforge-client.bat # Double-click, enter server/port/PSK
+tunnelforge-client.bat stop # Disconnect
+tunnelforge-client.bat status # Check
+# Set browser proxy: 127.0.0.1:1080
+```
+
+#### What DPI Sees
+
+```
+User PC ──── HTTPS:1443 ──► VPS-A IP (normal TLS)
+VPS-A ──── HTTPS:443 ──► VPS-B IP (normal TLS)
+No SSH protocol visible anywhere in the chain.
+```
+
+
+
+
+Scenario 7: Share Your Tunnel With Others
+
+**Goal:** You have a working tunnel with TLS+PSK protection and want to give others access. TunnelForge generates a standalone script they just run.
+
+**What you need:** A running tunnel with Inbound TLS+PSK enabled (see Scenario 5 or 6).
+
+#### Step 1 — Generate Client Scripts
+
+```bash
+tunnelforge client-script my-tunnel
+```
+
+This creates two files:
+- `tunnelforge-connect.sh` — for Linux/Mac
+- `tunnelforge-connect.ps1` — for Windows PowerShell
+
+Each script contains your server address, port, and PSK — everything needed to connect.
+
+**Or use the standalone Windows client:** Send users `windows-client/tunnelforge-client.bat` from the repo — they double-click it, enter connection details, and they're connected. No scripts to generate.
+
+#### Step 2 — Send to Users
+
+Share via:
+- Telegram: `tunnelforge telegram share my-tunnel`
+- WhatsApp, email, USB drive, or any file transfer method
+- For Windows users: also send `windows-client/tunnelforge-client.bat` (or just send the .bat alone with PSK info)
+
+#### Step 3 — User Runs the Script
+
+**Linux:**
+```bash
+chmod +x tunnelforge-connect.sh
+./tunnelforge-connect.sh # Connect (auto-installs stunnel if needed)
+./tunnelforge-connect.sh stop # Disconnect
+./tunnelforge-connect.sh status # Check connection
+```
+
+**Windows (PowerShell — generated script):**
+```powershell
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 stop
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 status
+```
+
+**Windows (Batch — standalone client):**
+```
+tunnelforge-client.bat # Double-click or run — enter server/port/PSK when prompted
+tunnelforge-client.bat stop # Disconnect
+tunnelforge-client.bat status # Check connection
+```
+
+All clients automatically:
+1. Install stunnel if not present (winget/Chocolatey/apt)
+2. Write config files locally
+3. Start stunnel and create a local SOCKS5 proxy
+4. Print browser setup instructions (Firefox + Chrome)
+
+#### After Connecting
+
+```
+Browser proxy: 127.0.0.1:1080
+All traffic routes through the tunnel.
+```
+
+#### View Connection Info Without Scripts
+
+```bash
+# Show PSK + server + port info (for manual setup):
+tunnelforge client-config my-tunnel
+```
+
+#### Revoking Access
+
+To revoke a user's access:
+1. Edit the profile and regenerate the PSK
+2. Regenerate client scripts: `tunnelforge client-script my-tunnel`
+3. Restart the tunnel: `tunnelforge restart my-tunnel`
+4. Old scripts will no longer work — distribute the new ones to authorized users only
+
+
+
+
+
+---
+
+
+Learn Menu (Built-in Education)
+
+TunnelForge includes an interactive learning system accessible from the main menu (`l` key) or CLI. Each topic includes explanations, ASCII diagrams, and practical examples.
+
+| # | Topic | Description |
+|---|---|---|
+| 1 | What is an SSH Tunnel? | Encrypted channel fundamentals |
+| 2 | SOCKS5 Dynamic Proxy | Route all traffic through `-D` flag |
+| 3 | Local Port Forwarding | Access remote services via `-L` flag |
+| 4 | Remote/Reverse Forwarding | Expose local services via `-R` flag |
+| 5 | Jump Hosts & Multi-hop | Chain through bastions via `-J` flag |
+| 6 | ControlMaster Multiplexing | Reuse SSH connections for speed |
+| 7 | AutoSSH & Reconnection | Automatic tunnel recovery |
+| 8 | What is TLS Obfuscation? | Wrap SSH in TLS to bypass DPI |
+| 9 | PSK Authentication | Pre-Shared Key for tunnel security |
+
+
+
+---
+
+## License & Author
+
+**TunnelForge** is licensed under the [GNU General Public License v3.0](LICENSE).
+
+Copyright (C) 2026 **SamNet Technologies, LLC**
+
+```
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+```
+
+---
+
+
+
+
+
+
+ ▀▀█▀▀ █ █ █▄ █ █▄ █ █▀▀ █ █▀▀ █▀█ █▀█ █▀▀ █▀▀
+ █ █ █ █ ▀█ █ ▀█ █▀▀ █ █▀ █ █ █▀█ █ █ █▀▀
+ █ ▀▀ █ █ █ █ ▀▀▀ ▀▀▀ █ ▀▀▀ █ █ ▀▀▀ ▀▀▀
+
+
+
+
+
کاملترین مدیر تانل SSH در یک فایل
+
+
+
+
+
+
+
+
+
+
+ یک اسکریپت. همه انواع تانل. رابط کاربری کامل. داشبورد زنده..
+ SOCKS5 • Local Forward • Remote Forward • Jump Host • رمزنگاری TLS • ربات تلگرام • Kill Switch • محافظت DNS
+
+
+---
+
+## شروع سریع
+
+**نصب با یک دستور:**
+
+
+```bash
+curl -fsSL https://git.samnet.dev/SamNet-dev/tunnelforge/raw/branch/main/tunnelforge.sh -o tunnelforge.sh && sudo bash tunnelforge.sh install
+```
+
+
+
+**یا کلون ریپو:**
+
+
+```bash
+git clone https://git.samnet.dev/SamNet-dev/tunnelforge.git
+cd tunnelforge
+sudo bash tunnelforge.sh install
+```
+
+
+
+**اجرای منوی تعاملی:**
+
+
+```bash
+tunnelforge menu
+```
+
+
+
+**یا استفاده مستقیم از CLI:**
+
+
+```bash
+tunnelforge create # ساخت اولین تانل
+tunnelforge start my-tunnel # شروع تانل
+tunnelforge dashboard # داشبورد زنده
+```
+
+
+
+
+
+
+ رابط کاربری تعاملی — مدیریت تانلها، امنیت، سرویسها و بیشتر از یک منو
+
+
+---
+
+## چرا TunnelForge؟
+
+بیشتر ابزارهای مدیریت تانل SSH یا خیلی ساده هستند (فقط یک wrapper روی `ssh -D`) یا خیلی پیچیده (نیاز به Docker، Go، Python یا دهها فایل تنظیمات). TunnelForge متفاوت است:
+
+| | TunnelForge | سایر ابزارها |
+|---|---|---|
+| **نصب** | یک فایل bash، بدون وابستگی | Python/Go/Node.js + package manager |
+| **رابط کاربری** | منوی TUI کامل + CLI + داشبورد زنده | فقط CLI یا Web UI |
+| **امنیت** | محافظت DNS، کیل سوییچ، امتیازدهی امنیتی | فقط SSH ساده |
+| **رمزنگاری** | پوشش TLS + PSK برای عبور از DPI | ندارد |
+| **مانیتورینگ** | نمودار پهنای باند لحظهای | فایلهای لاگ |
+| **اطلاعرسانی** | ربات تلگرام با دستورات ریموت | ندارد |
+| **پایداری** | سرویس systemd خودکار | تنظیم دستی |
+| **آموزش** | منوی یادگیری داخلی با دیاگرام | مستندات خارجی |
+| **اشتراکگذاری** | تولید اسکریپت اتصال (Linux + Windows) | تنظیم دستی |
+
+**TunnelForge کاملترین مدیر تانل SSH موجود در یک فایل است.**
+
+---
+
+
+مروری بر امکانات
+
+### مدیریت تانل
+- **پراکسی SOCKS5 داینامیک** (`-D`) — مسیریابی تمام ترافیک از طریق سرور SSH
+- **Port Forwarding محلی** (`-L`) — دسترسی محلی به سرویسهای ریموت
+- **Port Forwarding معکوس** (`-R`) — نمایش سرویسهای محلی به بیرون
+- **Jump Host / چند مرحلهای** (`-J`) — عبور از سرورهای واسط
+- **AutoSSH** — اتصال مجدد خودکار
+- **ControlMaster** — استفاده مجدد از اتصالات SSH
+- **چند تانل همزمان** — اجرای دهها تانل به صورت موازی
+
+### امنیت
+- **محافظت از نشت DNS** — بازنویسی resolv.conf + قفل با `chattr`
+- **کیل سوییچ** — مسدود کردن تمام ترافیک در صورت قطع تانل (IPv4 + IPv6)
+- **ممیزی امنیتی ۶ نقطهای** — ارزیابی امتیازی وضعیت امنیتی
+- **تولید کلید SSH** — ساخت کلیدهای ed25519، RSA یا ECDSA
+- **استقرار کلید SSH** — ارسال کلید به سرور با یک دستور
+- **تأیید اثرانگشت سرور** — بررسی هویت سرور قبل از اتصال
+- **سختسازی سرور** — تنظیم خودکار sshd، فایروال، fail2ban و sysctl
+
+### مانیتورینگ و داشبورد
+- **داشبورد TUI زنده** — وضعیت لحظهای تانلها با رفرش خودکار
+- **نمودار پهنای باند Sparkline** — نمودارهای ASCII (▁▂▃▄▅▆▇█) برای RX/TX
+- **شمارنده ترافیک** — کل بایتهای ارسال و دریافت هر تانل
+- **ردیابی Uptime** — نمایش زمان اتصال هر تانل
+- **کیفیت اتصال** — اندازهگیری تأخیر با نشانگر رنگی
+- **تست سرعت** — تست سرعت دانلود داخلی از طریق تانل
+- **صفحهبندی** — ناوبری در صفحات مختلف برای تانلهای زیاد
+
+
+
+
+ داشبورد زنده با نمودار پهنای باند، اتصالات فعال، لاگ اتصال مجدد و منابع سیستم
+
+
+### ربات تلگرام
+- **اعلانهای لحظهای** — شروع، توقف، خطا، اتصال مجدد
+- **دستورات ریموت** — `/tf_status`، `/tf_list`، `/tf_ip`، `/tf_config` و بیشتر
+- **گزارشهای دورهای** — ارسال زمانبندی شده وضعیت به گوشی
+- **اشتراکگذاری** — ارسال اسکریپت اتصال + PSK از طریق تلگرام
+- **مسیریابی SOCKS5** — ربات از طریق تانل کار میکند وقتی تلگرام مسدود است
+
+### رمزنگاری TLS (ضد سانسور)
+- **پوشش TLS خروجی** — ترافیک SSH به شکل HTTPS از طریق stunnel
+- **محافظت PSK ورودی** — لیسنر SOCKS5 با کلید پیشاشتراکی
+- **تولید اسکریپت کلاینت** — ساخت خودکار اسکریپت اتصال برای Linux + Windows
+- **راهاندازی خودکار سرور** — نصب و پیکربندی stunnel با یک دستور
+- **عبور از DPI** — ترافیک مانند HTTPS معمولی روی پورت 443
+
+### یکپارچگی سیستم
+- **تولیدکننده سرویس Systemd** — ساخت خودکار فایلهای unit امن
+- **پشتیبانگیری و بازیابی** — بکاپ کامل تنظیمات با چرخش
+- **ویزارد سختسازی سرور** — آمادهسازی سرور تازه برای دریافت تانل
+- **مدیریت پروفایل** — ساخت، ویرایش، حذف، وارد کردن پروفایل
+- **مدیریت لاگ** — لاگ مجزا برای هر تانل با چرخش
+- **حذف کامل** — پاکسازی تمام فایلها، سرویسها و تنظیمات
+
+### آموزش داخلی
+- **منوی یادگیری** — ۹ درس تعاملی درباره مفاهیم تانل SSH
+- **سناریوهای واقعی** — راهنمای گام به گام با دیاگرام
+- **دیاگرامهای ASCII** — نمایش بصری جریان ترافیک
+
+
+
+---
+
+
+انواع تانل
+
+### پراکسی SOCKS5 داینامیک (`-D`)
+
+**تمام** ترافیک TCP خود را از طریق سرور SSH مسیریابی کنید. ترافیک شما از IP سرور ارسال میشود.
+
+
+
+```
+Client :1080 ──── SSH (Encrypted) ────► Server ──── Direct ────► Internet
+```
+
+
+
+**کاربردها:** مرور خصوصی، عبور از محدودیتهای جغرافیایی، مخفی کردن IP، مسیریابی ترافیک.
+
+
+
+```bash
+tunnelforge create # انتخاب "SOCKS5 Proxy" → پورت 1080
+tunnelforge start my-proxy
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+```
+
+
+
+---
+
+### Port Forwarding محلی (`-L`)
+
+به یک **سرویس ریموت** دسترسی پیدا کنید انگار روی سیستم خودتان اجرا میشود.
+
+
+
+```
+Client :3306 ──── SSH (Encrypted) ────► Server ──── Local ────► MySQL :3306
+```
+
+
+
+**کاربردها:** دسترسی به دیتابیس ریموت، وب اپلیکیشنهای داخلی، پنلهای مدیریتی پشت فایروال.
+
+
+
+```bash
+tunnelforge create # انتخاب "Local Forward" → محلی 3306 → ریموت db:3306
+tunnelforge start db-tunnel
+mysql -h 127.0.0.1 -P 3306 -u admin -p
+```
+
+
+
+---
+
+### Port Forwarding معکوس (`-R`)
+
+یک **سرویس محلی** را از طریق سرور SSH در دسترس دنیای بیرون قرار دهید.
+
+
+
+```
+Local App :3000 ◄──── SSH (Encrypted) ────► Server :9090 ◄──── Users
+```
+
+
+
+**کاربردها:** توسعه webhook، اشتراکگذاری اپ برای تست، عبور از NAT، دمو به مشتری.
+
+
+
+```bash
+tunnelforge create # انتخاب "Remote Forward" → ریموت 9090 ← محلی 3000
+tunnelforge start dev-share
+```
+
+
+
+---
+
+### Jump Host / چند مرحلهای (`-J`)
+
+به سرورهایی که پشت **چندین لایه** فایروال هستند از طریق سرورهای واسط دسترسی پیدا کنید.
+
+
+
+```
+Client ── SSH ──► Jump 1 ── SSH ──► Jump 2 ── SSH ──► Target
+```
+
+
+
+**کاربردها:** شبکههای سازمانی، معماری چند لایه، محیطهای ایزوله، مناطق امنیتی.
+
+
+
+---
+
+
+نصب
+
+### پیشنیازها
+
+| پیشنیاز | جزئیات |
+|---|---|
+| **سیستم عامل** | Linux (Ubuntu، Debian، CentOS، Fedora، Arch، Alpine) |
+| **Bash** | نسخه ۴.۳ یا بالاتر |
+| **دسترسی** | دسترسی root برای نصب |
+| **SSH** | کلاینت OpenSSH (در اکثر سیستمها نصب است) |
+| **اختیاری** | `autossh` (اتصال مجدد خودکار)، `stunnel` (رمزنگاری TLS)، `sshpass` (احراز هویت با رمز) |
+
+### نصب
+
+
+
+```bash
+# روش ۱: کلون از Git
+git clone https://git.samnet.dev/SamNet-dev/tunnelforge.git
+cd tunnelforge
+sudo bash tunnelforge.sh install
+
+# روش ۲: دانلود مستقیم
+curl -fsSL https://git.samnet.dev/SamNet-dev/tunnelforge/raw/branch/main/tunnelforge.sh -o tunnelforge.sh
+sudo bash tunnelforge.sh install
+```
+
+
+
+### تأیید نصب
+
+
+
+```bash
+tunnelforge version
+# TunnelForge v1.0.0
+```
+
+
+
+### ساختار دایرکتوری
+
+
+
+```
+/opt/tunnelforge/
+├── tunnelforge.sh # اسکریپت اصلی
+├── config/
+│ └── tunnelforge.conf # تنظیمات کلی
+├── profiles/
+│ └── *.conf # پروفایل تانلها
+├── pids/ # فایلهای PID تانلهای فعال
+├── logs/ # لاگ هر تانل
+├── backups/ # فایلهای پشتیبان
+├── data/
+│ ├── bandwidth/ # تاریخچه پهنای باند
+│ └── reconnects/ # آمار اتصال مجدد
+└── sockets/ # سوکتهای ControlMaster
+```
+
+
+
+
+
+---
+
+
+مثالهای سریع
+
+### مرور خصوصی با SOCKS5
+
+
+
+```bash
+tunnelforge create
+# → نام: private-proxy
+# → نوع: SOCKS5
+# → سرور: user@myserver.com
+# → پورت: 1080
+
+tunnelforge start private-proxy
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+
+# تنظیم فایرفاکس: Settings → Network → Manual Proxy → SOCKS5: 127.0.0.1:1080
+```
+
+
+
+### دسترسی به دیتابیس ریموت
+
+
+
+```bash
+tunnelforge create
+# → نام: prod-db
+# → نوع: Local Forward
+# → سرور: admin@db-server.internal
+# → پورت محلی: 3306 → ریموت: localhost:3306
+
+tunnelforge start prod-db
+mysql -h 127.0.0.1 -P 3306 -u dbuser -p
+```
+
+
+
+### اشتراکگذاری سرور توسعه
+
+
+
+```bash
+tunnelforge create
+# → نام: demo-share
+# → نوع: Remote Forward
+# → سرور: user@public-vps.com
+# → پورت ریموت: 8080 ← محلی: localhost:3000
+
+tunnelforge start demo-share
+# لینک اشتراک: http://public-vps.com:8080
+```
+
+
+
+### عبور از سانسور با رمزنگاری TLS
+
+
+
+```bash
+# ۱. راهاندازی stunnel روی VPS
+tunnelforge obfs-setup my-tunnel
+
+# ۲. شروع تانل — SSH حالا در TLS پورت 443 پوشش داده شده
+tunnelforge start my-tunnel
+
+# DPI میبیند: ترافیک HTTPS عادی
+# واقعیت: تانل SSH داخل TLS
+
+# ۳. اشتراک با دیگران
+tunnelforge client-script my-tunnel # تولید اسکریپت اتصال
+tunnelforge telegram share my-tunnel # ارسال از طریق تلگرام
+```
+
+
+
+
+
+---
+
+
+مرجع دستورات CLI
+
+### دستورات تانل
+
+| دستور | توضیح |
+|---|---|
+| `tunnelforge start ` | شروع تانل |
+| `tunnelforge stop ` | توقف تانل |
+| `tunnelforge restart ` | راهاندازی مجدد |
+| `tunnelforge start-all` | شروع همه تانلهای خودکار |
+| `tunnelforge stop-all` | توقف همه تانلها |
+| `tunnelforge status` | نمایش وضعیت |
+| `tunnelforge dashboard` | داشبورد زنده |
+| `tunnelforge logs [name]` | مشاهده لاگ |
+
+### دستورات پروفایل
+
+| دستور | توضیح |
+|---|---|
+| `tunnelforge create` | ساخت پروفایل جدید (ویزارد) |
+| `tunnelforge list` | لیست پروفایلها |
+| `tunnelforge delete ` | حذف پروفایل |
+
+### دستورات امنیتی
+
+| دستور | توضیح |
+|---|---|
+| `tunnelforge audit` | ممیزی امنیتی ۶ نقطهای |
+| `tunnelforge key-gen [type]` | تولید کلید SSH |
+| `tunnelforge key-deploy ` | استقرار کلید روی سرور |
+| `tunnelforge fingerprint ` | بررسی اثرانگشت سرور |
+
+### دستورات تلگرام
+
+| دستور | توضیح |
+|---|---|
+| `tunnelforge telegram setup` | پیکربندی ربات |
+| `tunnelforge telegram test` | ارسال پیام آزمایشی |
+| `tunnelforge telegram status` | نمایش تنظیمات |
+| `tunnelforge telegram send ` | ارسال پیام |
+| `tunnelforge telegram report` | ارسال گزارش وضعیت |
+| `tunnelforge telegram share [name]` | اشتراک اسکریپتها |
+
+### دستورات سرویس
+
+| دستور | توضیح |
+|---|---|
+| `tunnelforge service ` | تولید سرویس systemd |
+| `tunnelforge service enable` | فعالسازی سرویس |
+| `tunnelforge service disable` | غیرفعالسازی |
+| `tunnelforge service status` | وضعیت سرویس |
+| `tunnelforge service remove` | حذف سرویس |
+
+### دستورات سیستم
+
+| دستور | توضیح |
+|---|---|
+| `tunnelforge menu` | منوی تعاملی |
+| `tunnelforge install` | نصب TunnelForge |
+| `tunnelforge server-setup` | سختسازی سرور |
+| `tunnelforge obfs-setup ` | راهاندازی رمزنگاری TLS |
+| `tunnelforge client-config ` | نمایش تنظیمات کلاینت |
+| `tunnelforge client-script ` | تولید اسکریپت کلاینت |
+| `tunnelforge backup` | پشتیبانگیری |
+| `tunnelforge restore [file]` | بازیابی |
+| `tunnelforge uninstall` | حذف کامل |
+| `tunnelforge version` | نمایش نسخه |
+| `tunnelforge help` | راهنما |
+
+
+
+---
+
+
+امنیت
+
+### محافظت از نشت DNS
+
+از ارسال درخواستهای DNS خارج از تانل جلوگیری میکند.
+
+**نحوه کار:**
+1. از `/etc/resolv.conf` فعلی بکاپ میگیرد
+2. آن را با سرورهای DNS امن بازنویسی میکند (پیشفرض: 8.8.8.8)
+3. فایل را با `chattr +i` قفل میکند تا سیستم نتواند آن را تغییر دهد
+4. هنگام توقف تانل، DNS اصلی بازیابی میشود
+
+### کیل سوییچ
+
+اگر تانل قطع شود، **تمام ترافیک اینترنت مسدود میشود**.
+
+**نحوه کار:**
+1. زنجیره iptables سفارشی `TUNNELFORGE` ایجاد میکند
+2. فقط ترافیک تانل SSH + loopback مجاز است
+3. بقیه ترافیک مسدود (IPv4 + IPv6)
+4. هنگام توقف تانل، قوانین حذف میشوند
+
+### ممیزی امنیتی ۶ نقطهای
+
+
+
+```bash
+tunnelforge audit
+```
+
+
+
+| بررسی | توضیح |
+|---|---|
+| مجوزهای کلید SSH | بررسی 600 یا 400 بودن |
+| دایرکتوری SSH | تأیید 700 بودن `~/.ssh` |
+| محافظت DNS | وضعیت محافظت فعال |
+| کیل سوییچ | فعال بودن زنجیره iptables |
+| سلامت تانل | بررسی اعتبار PIDها |
+| بستههای سیستم | ابزارهای امنیتی نصب شده |
+
+### سختسازی سرور
+
+
+
+```bash
+tunnelforge server-setup
+```
+
+
+
+**تنظیمات:**
+- **SSH** — غیرفعالسازی احراز هویت رمز عبور، غیرفعالسازی root login
+- **فایروال** — قوانین UFW/iptables فقط برای SSH + پورتهای تانل
+- **Fail2ban** — مسدودسازی خودکار بعد از تلاشهای ناموفق
+- **Kernel** — سختسازی sysctl (محافظت SYN flood، ICMP)
+
+
+
+---
+
+
+رمزنگاری TLS (ضد سانسور)
+
+در شبکههایی که بازرسی عمیق بسته (DPI) دارند، ترافیک SSH قابل شناسایی و مسدودسازی است. TunnelForge اتصال SSH شما را داخل یک لایه TLS میپیچد تا مانند ترافیک HTTPS عادی به نظر برسد.
+
+### نحوه کار
+
+
+
+```
+بدون رمزنگاری TLS:
+Client ──── SSH (قابل شناسایی) ────► VPS ← DPI میتواند مسدود کند
+
+با رمزنگاری TLS:
+Client ──── TLS/443 (شبیه HTTPS) ────► VPS ──── SSH ────► اینترنت
+```
+
+
+
+### راهاندازی سمت سرور
+
+
+
+```bash
+tunnelforge obfs-setup my-tunnel
+```
+
+
+
+این دستور به صورت خودکار:
+1. `stunnel` را روی سرور ریموت نصب میکند
+2. گواهی TLS خودامضا تولید میکند
+3. پورت 443 (TLS) را به پورت 22 (SSH) مپ میکند
+4. سرویس systemd فعال میکند
+5. پورت فایروال باز میکند
+
+### اشتراکگذاری با دیگران
+
+
+
+```bash
+# تولید اسکریپت برای Linux + Windows
+tunnelforge client-script my-tunnel
+
+# ارسال از طریق تلگرام
+tunnelforge telegram share my-tunnel
+```
+
+
+
+اسکریپتهای تولید شده شامل تنظیمات stunnel، فایل PSK و مدیریت کامل اتصال هستند.
+
+### کلاینت مستقل ویندوز
+
+فایل **[`windows-client/tunnelforge-client.bat`](windows-client/tunnelforge-client.bat)** یک کلاینت مستقل ویندوز است که در ریپو موجود است. کاربران فقط دابلکلیک میکنند، اطلاعات اتصال را وارد میکنند و متصل میشوند. نیازی به PowerShell نیست.
+
+**امکانات:**
+- تنظیم تعاملی — سرور، پورت و PSK را میپرسد
+- نصب خودکار stunnel (از طریق winget، Chocolatey یا لینک دانلود)
+- ذخیره اتصال برای اتصال مجدد فوری
+- دستورات: `tunnelforge-client.bat stop` / `status`
+- نمایش تنظیمات پراکسی مرورگر (Firefox + Chrome)
+
+
+
+```
+توزیع:
+1. فایل windows-client/tunnelforge-client.bat را به کاربر بدهید
+2. اطلاعات PSK + سرور را بدهید (از: tunnelforge client-config
)
+3. کاربر دابلکلیک → اطلاعات وارد → متصل
+```
+
+
+
+
+
+---
+
+
+ربات تلگرام
+
+اطلاعرسانی لحظهای تانلها روی گوشی و کنترل ریموت.
+
+### راهاندازی
+
+
+
+```bash
+tunnelforge telegram setup
+```
+
+
+
+1. **ساخت ربات** — به [@BotFather](https://t.me/BotFather) پیام دهید و `/newbot` ارسال کنید
+2. **وارد کردن توکن** — توکن ربات را در TunnelForge وارد کنید
+3. **دریافت Chat ID** — به ربات `/start` ارسال کنید، TunnelForge خودکار شناسایی میکند
+4. **تمام** — پیام آزمایشی تأیید ارسال میشود
+
+### اعلانها
+
+| رویداد | پیام |
+|---|---|
+| شروع تانل | نام، PID، نوع تانل |
+| توقف تانل | نام پروفایل |
+| خطای تانل | جزئیات خطا |
+| اتصال مجدد | بازیابی خودکار AutoSSH |
+| هشدار امنیتی | نشت DNS یا کیل سوییچ |
+| گزارش وضعیت | مرور کلی تمام تانلها |
+
+### دستورات ربات
+
+| دستور | پاسخ |
+|---|---|
+| `/tf_status` | وضعیت تمام تانلها |
+| `/tf_list` | لیست پروفایلها |
+| `/tf_ip` | IP عمومی سرور |
+| `/tf_config` | تنظیمات اتصال کلاینت |
+| `/tf_uptime` | مدت فعالیت سرور |
+| `/tf_report` | گزارش کامل وضعیت |
+| `/tf_help` | لیست دستورات |
+
+
+
+---
+
+
+سرویس Systemd
+
+تانلها را مقاوم در برابر ریبوت کنید:
+
+
+
+```bash
+tunnelforge service my-tunnel # تولید فایل سرویس
+tunnelforge service my-tunnel enable # فعالسازی و شروع
+tunnelforge service my-tunnel status # بررسی وضعیت
+tunnelforge service my-tunnel disable # غیرفعالسازی
+tunnelforge service my-tunnel remove # حذف سرویس
+```
+
+
+
+فایل سرویس تولید شده شامل سختسازی امنیتی (`ProtectSystem`، `PrivateTmp`، قابلیتهای محدود) است.
+
+
+
+---
+
+
+پشتیبانگیری و بازیابی
+
+
+
+```bash
+# پشتیبانگیری
+tunnelforge backup
+
+# بازیابی
+tunnelforge restore
+tunnelforge restore /path/to/backup.tar.gz
+```
+
+
+
+شامل: پروفایلها، تنظیمات، کلیدهای SSH و فایلهای سرویس systemd.
+
+
+
+---
+
+
+سناریوهای واقعی
+
+هر سناریو قابل باز شدن است و **مراحل دقیق ویزارد** را نشان میدهد. هم نسخه SSH معمولی و هم TLS رمزنگاری شده پوشش داده شده.
+
+
+سناریو ۱: مرور خصوصی با SOCKS5
+
+**هدف:** ترافیک مرورگر را از طریق VPS مسیریابی کنید تا سایتها IP سرور را ببینند نه IP واقعی شما.
+
+**پیشنیاز:** یک سرور VPS با دسترسی SSH.
+
+#### مراحل ویزارد (SSH معمولی)
+
+
+
+```
+tunnelforge create
+```
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 1 | Profile name | `private-proxy` |
+| 2 | Tunnel type | `1` — SOCKS5 Proxy |
+| 3 | SSH host | IP سرور (مثلاً `45.33.32.10`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `root` |
+| 6 | SSH password | رمز عبور (یا Enter برای کلید SSH) |
+| 7 | Identity key | `~/.ssh/id_ed25519` (یا Enter) |
+| 8 | Auth test | خودکار |
+| 9a | Bind address | `127.0.0.1` |
+| 9b | SOCKS5 port | `1080` |
+| 10 | Connection mode | `1` — Regular SSH |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` سپس `y` |
+
+
+
+#### مراحل ویزارد (TLS رمزنگاری — برای شبکه سانسور شده)
+
+مانند بالا، اما در مرحله ۱۰:
+
+
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 10 | Connection mode | `2` — TLS Encrypted |
+| 10a | TLS port | `443` (شبیه HTTPS) |
+| 10b | Setup stunnel now? | `y` (نصب خودکار روی سرور) |
+
+
+
+#### بعد از شروع
+
+
+
+**Firefox:** Settings → proxy → SOCKS Host: `127.0.0.1` Port: `1080`
+
+**Chrome:**
+```bash
+google-chrome --proxy-server="socks5://127.0.0.1:1080"
+```
+
+**تست:**
+```bash
+curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
+```
+
+
+
+
+
+
+سناریو ۲: دسترسی به دیتابیس ریموت
+
+**هدف:** به MySQL/PostgreSQL روی VPS دسترسی پیدا کنید انگار روی سیستم خودتان اجرا میشود.
+
+**پیشنیاز:** یک VPS با دیتابیس فعال.
+
+#### مراحل ویزارد
+
+
+
+```
+tunnelforge create
+```
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 1 | Profile name | `prod-db` |
+| 2 | Tunnel type | `2` — Local Port Forward |
+| 3 | SSH host | IP سرور (مثلاً `45.33.32.10`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `root` |
+| 6 | SSH password | رمز عبور |
+| 7 | Identity key | Enter |
+| 8 | Auth test | خودکار |
+| 9a | Bind address | `127.0.0.1` |
+| 9b | Local port | `3306` (پورت روی سیستم شما) |
+| 9c | Remote host | `127.0.0.1` (یعنی "روی خود VPS") |
+| 9d | Remote port | `3306` (پورت MySQL روی VPS) |
+| 10 | Connection mode | `1` — Regular SSH |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` سپس `y` |
+
+
+
+#### بعد از شروع
+
+
+
+```bash
+mysql -h 127.0.0.1 -P 3306 -u dbuser -p # MySQL
+psql -h 127.0.0.1 -p 5432 -U postgres # PostgreSQL
+redis-cli -h 127.0.0.1 -p 6379 # Redis
+```
+
+
+
+| سرویس | پورت محلی | پورت ریموت |
+|---|---|---|
+| MySQL | 3306 | 3306 |
+| PostgreSQL | 5432 | 5432 |
+| Redis | 6379 | 6379 |
+| پنل وب | 8080 | 8080 |
+
+
+
+
+سناریو ۳: اشتراکگذاری سرور توسعه
+
+**هدف:** وبسایت محلی (مثلاً پورت 3000) را از طریق VPS در دسترس اینترنت قرار دهید.
+
+**پیشنیاز:** یک سرویس محلی فعال + VPS با IP عمومی.
+
+#### مراحل ویزارد
+
+
+
+```
+tunnelforge create
+```
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 1 | Profile name | `dev-share` |
+| 2 | Tunnel type | `3` — Remote/Reverse Forward |
+| 3 | SSH host | IP سرور (مثلاً `45.33.32.10`) |
+| 4-8 | SSH credentials | مانند سناریوهای قبل |
+| 9a | Remote bind | `0.0.0.0` (دسترسی عمومی) |
+| 9b | Remote port | `9090` (پورت روی VPS) |
+| 9c | Local host | `127.0.0.1` |
+| 9d | Local port | `3000` (اپ شما) |
+| 10 | Connection mode | `1` — Regular SSH |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` سپس `y` |
+
+
+
+**مهم:** اگر bind روی `0.0.0.0` است، باید `GatewayPorts yes` در sshd سرور فعال باشد.
+
+#### بعد از شروع
+
+
+
+```bash
+# تست از هرجا:
+curl http://45.33.32.10:9090
+
+# لینک اشتراک: http://45.33.32.10:9090
+```
+
+
+
+
+
+
+سناریو ۴: عبور از چند فایروال (Jump Host)
+
+**هدف:** به سروری که مستقیماً از اینترنت قابل دسترسی نیست از طریق سرورهای واسط (bastion) دسترسی پیدا کنید.
+
+#### مراحل ویزارد (SOCKS5 در مقصد)
+
+
+
+```
+tunnelforge create
+```
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 1 | Profile name | `corp-access` |
+| 2 | Tunnel type | `4` — Jump Host |
+| 3 | SSH host | IP **مقصد** (مثلاً `10.0.50.100`) |
+| 4 | SSH port | `22` |
+| 5 | SSH user | `admin` (کاربر روی **مقصد**) |
+| 6 | SSH password | رمز **مقصد** |
+| 8 | Auth test | ممکن است خطا بدهد — ادامه دهید |
+| 9a | Jump hosts | `root@bastion.example.com:22` |
+| 9b | Tunnel type at destination | `1` — SOCKS5 |
+| 9c | Bind address | `127.0.0.1` |
+| 9d | SOCKS5 port | `1080` |
+| 10 | Connection mode | `1` — Regular SSH |
+| 13 | Save & start | `y` سپس `y` |
+
+
+
+> **مهم:** مراحل ۳ تا ۷ برای سرور **مقصد** هستند. اطلاعات سرور واسط در مرحله 9a وارد میشود.
+
+#### چند سرور واسط
+
+
+
+```
+Jump hosts: user1@hop1.com:22,user2@hop2.com:22
+```
+
+
+
+
+
+
+سناریو ۵: عبور از سانسور DPI (یک VPS)
+
+**هدف:** ISP شما SSH را شناسایی و مسدود میکند. SSH را در TLS بپیچید تا مانند HTTPS عادی به نظر برسد.
+
+
+
+```
+بدون TLS: PC ──── SSH (مسدود توسط DPI) ────► VPS
+با TLS: PC ──── TLS/443 (شبیه HTTPS) ────► VPS ──► Internet
+```
+
+
+
+#### مراحل ویزارد
+
+
+
+```
+tunnelforge create
+```
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 1 | Profile name | `bypass-proxy` |
+| 2 | Tunnel type | `1` — SOCKS5 Proxy |
+| 3 | SSH host | IP سرور خارج از کشور |
+| 4-8 | SSH credentials | مانند سناریوهای قبل |
+| 9a | Bind address | `127.0.0.1` |
+| 9b | SOCKS5 port | `1080` |
+| **10** | **Connection mode** | **`2` — TLS Encrypted** |
+| 10a | TLS port | `443` (شبیه HTTPS) |
+| 10b | Setup stunnel? | `y` (نصب خودکار) |
+| 11 | Inbound protection | `1` — None |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` سپس `y` |
+
+
+
+#### DPI چه میبیند
+
+
+
+```
+PC ──── HTTPS:443 ──► VPS IP
+نتیجه: ترافیک عادی وب. مجاز.
+```
+
+
+
+
+
+
+سناریو ۶: زنجیره دو سرور TLS
+
+**هدف:** پراکسی اشتراکی برای چند کاربر. VPS-A = ورودی (relay). VPS-B = خروجی. هر دو مسیر TLS رمزنگاری شده.
+
+
+
+```
+Users ── TLS+PSK:1443 ──► VPS-A ── TLS:443 ──► VPS-B ──► Internet
+```
+
+
+
+#### مراحل ویزارد (اجرا روی VPS-A)
+
+
+
+```
+tunnelforge create
+```
+
+| مرحله | سوال | چه وارد کنید |
+|---|---|---|
+| 1 | Profile name | `double-hop` |
+| 2 | Tunnel type | `1` — SOCKS5 |
+| 3 | SSH host | IP **VPS-B** |
+| 4-8 | SSH credentials | اطلاعات VPS-B |
+| 9a | Bind address | `127.0.0.1` |
+| 9b | SOCKS5 port | `1080` |
+| **10** | **Connection mode** | **`2` — TLS Encrypted** |
+| 10a | TLS port | `443` |
+| 10b | Setup stunnel on VPS-B? | `y` |
+| **11** | **Inbound protection** | **`2` — TLS + PSK** |
+| 11a | Inbound TLS port | `1443` |
+| 11b | PSK | خودکار تولید میشود |
+| 12 | AutoSSH | `y` |
+| 13 | Save & start | `y` سپس `y` |
+
+
+
+#### تولید اسکریپت برای کاربران
+
+
+
+```bash
+tunnelforge client-script double-hop # تولید اسکریپت
+tunnelforge telegram share double-hop # ارسال با تلگرام
+```
+
+
+
+#### کاربران چه میکنند
+
+
+
+```bash
+# Linux:
+./tunnelforge-connect.sh # اتصال
+./tunnelforge-connect.sh stop # قطع
+# پراکسی مرورگر: 127.0.0.1:1080
+```
+
+```powershell
+# Windows PowerShell:
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1
+# پراکسی مرورگر: 127.0.0.1:1080
+```
+
+```
+# Windows Batch (کلاینت مستقل):
+tunnelforge-client.bat # دابلکلیک، سرور/پورت/PSK وارد کنید
+tunnelforge-client.bat stop # قطع
+tunnelforge-client.bat status # بررسی
+# پراکسی مرورگر: 127.0.0.1:1080
+```
+
+
+
+
+
+
+سناریو ۷: اشتراک تانل با دیگران
+
+**هدف:** تانل TLS+PSK فعال دارید و میخواهید دیگران هم استفاده کنند. TunnelForge یک اسکریپت مستقل تولید میکند.
+
+**پیشنیاز:** تانل فعال با Inbound TLS+PSK (سناریو ۵ یا ۶).
+
+#### مرحله ۱ — تولید اسکریپت
+
+
+
+```bash
+tunnelforge client-script my-tunnel
+```
+
+
+
+دو فایل تولید میشود:
+- `tunnelforge-connect.sh` — برای Linux/Mac
+- `tunnelforge-connect.ps1` — برای Windows PowerShell
+
+**یا از کلاینت مستقل ویندوز استفاده کنید:** فایل `windows-client/tunnelforge-client.bat` را از ریپو به کاربر بدهید — فقط دابلکلیک، اطلاعات اتصال وارد، متصل. نیازی به تولید اسکریپت نیست.
+
+#### مرحله ۲ — ارسال به کاربران
+
+
+
+```bash
+tunnelforge telegram share my-tunnel # ارسال با تلگرام
+```
+
+
+
+یا از طریق واتساپ، ایمیل، فلش و غیره.
+
+برای کاربران ویندوز: فایل `windows-client/tunnelforge-client.bat` را هم بفرستید (یا فقط فایل bat با اطلاعات PSK کافیست).
+
+#### مرحله ۳ — اجرا توسط کاربر
+
+
+
+```bash
+# Linux:
+chmod +x tunnelforge-connect.sh
+./tunnelforge-connect.sh # اتصال (stunnel خودکار نصب میشود)
+./tunnelforge-connect.sh stop # قطع
+./tunnelforge-connect.sh status # بررسی وضعیت
+# پراکسی مرورگر: 127.0.0.1:1080
+```
+
+```powershell
+# Windows PowerShell:
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 stop
+powershell -ExecutionPolicy Bypass -File tunnelforge-connect.ps1 status
+# پراکسی مرورگر: 127.0.0.1:1080
+```
+
+```
+# Windows Batch (کلاینت مستقل):
+tunnelforge-client.bat # دابلکلیک، سرور/پورت/PSK وارد کنید
+tunnelforge-client.bat stop # قطع
+tunnelforge-client.bat status # بررسی
+# پراکسی مرورگر: 127.0.0.1:1080
+```
+
+
+
+#### لغو دسترسی کاربر
+
+1. PSK را در پروفایل تغییر دهید
+2. اسکریپت جدید تولید کنید: `tunnelforge client-script my-tunnel`
+3. تانل را ریستارت کنید: `tunnelforge restart my-tunnel`
+4. اسکریپتهای قدیمی دیگر کار نمیکنند
+
+
+
+
+
+---
+
+
+منوی یادگیری
+
+TunnelForge شامل سیستم آموزشی تعاملی است (کلید `l` در منوی اصلی):
+
+| # | موضوع | توضیح |
+|---|---|---|
+| ۱ | تانل SSH چیست؟ | مبانی کانال رمزنگاری شده |
+| ۲ | پراکسی SOCKS5 | مسیریابی ترافیک با `-D` |
+| ۳ | Port Forwarding محلی | دسترسی به سرویس ریموت با `-L` |
+| ۴ | Port Forwarding معکوس | نمایش سرویس محلی با `-R` |
+| ۵ | Jump Host | عبور از سرورهای واسط با `-J` |
+| ۶ | ControlMaster | استفاده مجدد از اتصالات |
+| ۷ | AutoSSH | بازیابی خودکار تانل |
+| ۸ | رمزنگاری TLS | پوشش SSH در TLS |
+| ۹ | احراز هویت PSK | کلید پیشاشتراکی |
+
+
+
+---
+
+## مجوز و نویسنده
+
+**TunnelForge** تحت مجوز [GNU General Public License v3.0](LICENSE) منتشر شده است.
+
+حق نشر (C) ۲۰۲۶ **SamNet Technologies, LLC**
+
+
diff --git a/screenshots/dashboard.png b/screenshots/dashboard.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a0900ec67d7e3d0d7f7bb1d6fd2e5275194bb3f
GIT binary patch
literal 73358
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