example_tsnet_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package tsnet_test
  4. import (
  5. "flag"
  6. "fmt"
  7. "log"
  8. "net/http"
  9. "net/http/httputil"
  10. "net/url"
  11. "os"
  12. "path/filepath"
  13. "tailscale.com/tsnet"
  14. )
  15. // ExampleServer shows you how to construct a ready-to-use tsnet instance.
  16. func ExampleServer() {
  17. srv := new(tsnet.Server)
  18. if err := srv.Start(); err != nil {
  19. log.Fatalf("can't start tsnet server: %v", err)
  20. }
  21. defer srv.Close()
  22. }
  23. // ExampleServer_hostname shows you how to set a tsnet server's hostname.
  24. //
  25. // This setting lets you control the host name of your program on your
  26. // tailnet. By default this will be the name of your program (such as foo
  27. // for a program stored at /usr/local/bin/foo). You can also override this
  28. // by setting the Hostname field.
  29. func ExampleServer_hostname() {
  30. srv := &tsnet.Server{
  31. Hostname: "kirito",
  32. }
  33. // do something with srv
  34. _ = srv
  35. }
  36. // ExampleServer_dir shows you how to configure the persistent directory for
  37. // a tsnet application. This is where the Tailscale node information is stored
  38. // so that your application can reconnect to your tailnet when the application
  39. // is restarted.
  40. //
  41. // By default, tsnet will store data in your user configuration directory based
  42. // on the name of the binary. Note that this folder must already exist or tsnet
  43. // calls will fail.
  44. func ExampleServer_dir() {
  45. dir := filepath.Join("/data", "tsnet")
  46. if err := os.MkdirAll(dir, 0700); err != nil {
  47. log.Fatal(err)
  48. }
  49. srv := &tsnet.Server{
  50. Dir: dir,
  51. }
  52. // do something with srv
  53. _ = srv
  54. }
  55. // ExampleServer_multipleInstances shows you how to configure multiple instances
  56. // of tsnet per program. This allows you to have multiple Tailscale nodes in the
  57. // same process/container.
  58. func ExampleServer_multipleInstances() {
  59. baseDir := "/data"
  60. var servers []*tsnet.Server
  61. for _, hostname := range []string{"ichika", "nino", "miku", "yotsuba", "itsuki"} {
  62. os.MkdirAll(filepath.Join(baseDir, hostname), 0700)
  63. srv := &tsnet.Server{
  64. Hostname: hostname,
  65. AuthKey: os.Getenv("TS_AUTHKEY"),
  66. Ephemeral: true,
  67. Dir: filepath.Join(baseDir, hostname),
  68. }
  69. if err := srv.Start(); err != nil {
  70. log.Fatalf("can't start tsnet server: %v", err)
  71. }
  72. servers = append(servers, srv)
  73. }
  74. // When you're done, close the instances
  75. defer func() {
  76. for _, srv := range servers {
  77. srv.Close()
  78. }
  79. }()
  80. }
  81. // ExampleServer_ignoreLogsSometimes shows you how to ignore all of the log messages
  82. // written by a tsnet instance, but allows you to opt-into them if a command-line
  83. // flag is set.
  84. func ExampleServer_ignoreLogsSometimes() {
  85. tsnetVerbose := flag.Bool("tsnet-verbose", false, "if set, verbosely log tsnet information")
  86. hostname := flag.String("tsnet-hostname", "hikari", "hostname to use on the tailnet")
  87. srv := &tsnet.Server{
  88. Hostname: *hostname,
  89. }
  90. if *tsnetVerbose {
  91. srv.Logf = log.New(os.Stderr, fmt.Sprintf("[tsnet:%s] ", *hostname), log.LstdFlags).Printf
  92. }
  93. }
  94. // ExampleServer_HTTPClient shows you how to make HTTP requests over your tailnet.
  95. //
  96. // If you want to make outgoing HTTP connections to resources on your tailnet, use
  97. // the HTTP client that the tsnet.Server exposes.
  98. func ExampleServer_HTTPClient() {
  99. srv := &tsnet.Server{}
  100. cli := srv.HTTPClient()
  101. resp, err := cli.Get("https://hello.ts.net")
  102. if resp == nil {
  103. log.Fatal(err)
  104. }
  105. // do something with resp
  106. _ = resp
  107. }
  108. // ExampleServer_Start demonstrates the Start method, which should be called if
  109. // you need to explicitly start it. Note that the Start method is implicitly
  110. // called if needed.
  111. func ExampleServer_Start() {
  112. srv := new(tsnet.Server)
  113. if err := srv.Start(); err != nil {
  114. log.Fatal(err)
  115. }
  116. // Be sure to close the server instance at some point. It will stay open until
  117. // either the OS process ends or the server is explicitly closed.
  118. defer srv.Close()
  119. }
  120. // ExampleServer_Listen shows you how to create a TCP listener on your tailnet and
  121. // then makes an HTTP server on top of that.
  122. func ExampleServer_Listen() {
  123. srv := &tsnet.Server{
  124. Hostname: "tadaima",
  125. }
  126. ln, err := srv.Listen("tcp", ":80")
  127. if err != nil {
  128. log.Fatal(err)
  129. }
  130. log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  131. fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
  132. })))
  133. }
  134. // ExampleServer_ListenTLS shows you how to create a TCP listener on your tailnet and
  135. // then makes an HTTPS server on top of that.
  136. func ExampleServer_ListenTLS() {
  137. srv := &tsnet.Server{
  138. Hostname: "aegis",
  139. }
  140. ln, err := srv.ListenTLS("tcp", ":443")
  141. if err != nil {
  142. log.Fatal(err)
  143. }
  144. log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  145. fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
  146. })))
  147. }
  148. // ExampleServer_ListenFunnel shows you how to create an HTTPS service on both your tailnet
  149. // and the public internet via Funnel.
  150. func ExampleServer_ListenFunnel() {
  151. srv := &tsnet.Server{
  152. Hostname: "ophion",
  153. }
  154. ln, err := srv.ListenFunnel("tcp", ":443")
  155. if err != nil {
  156. log.Fatal(err)
  157. }
  158. log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  159. fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
  160. })))
  161. }
  162. // ExampleServer_ListenFunnel_funnelOnly shows you how to create a funnel-only HTTPS service.
  163. func ExampleServer_ListenFunnel_funnelOnly() {
  164. srv := new(tsnet.Server)
  165. srv.Hostname = "ophion"
  166. ln, err := srv.ListenFunnel("tcp", ":443", tsnet.FunnelOnly())
  167. if err != nil {
  168. log.Fatal(err)
  169. }
  170. log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  171. fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
  172. })))
  173. }
  174. // ExampleServer_ListenService demonstrates how to advertise an HTTPS Service.
  175. func ExampleServer_ListenService() {
  176. s := &tsnet.Server{
  177. Hostname: "tsnet-services-demo",
  178. }
  179. defer s.Close()
  180. ln, err := s.ListenService("svc:my-service", tsnet.ServiceModeHTTP{
  181. HTTPS: true,
  182. Port: 443,
  183. })
  184. if err != nil {
  185. log.Fatal(err)
  186. }
  187. defer ln.Close()
  188. log.Printf("Listening on https://%v\n", ln.FQDN)
  189. log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  190. fmt.Fprintln(w, "<html><body><h1>Hello, tailnet!</h1>")
  191. })))
  192. }
  193. // ExampleServer_ListenService_reverseProxy demonstrates how to advertise a
  194. // Service targeting a reverse proxy. This is useful when the backing server is
  195. // external to the tsnet application.
  196. func ExampleServer_ListenService_reverseProxy() {
  197. // targetAddress represents the address of the backing server.
  198. const targetAddress = "1.2.3.4:80"
  199. // We will use a reverse proxy to direct traffic to the backing server.
  200. reverseProxy := httputil.NewSingleHostReverseProxy(&url.URL{
  201. Scheme: "http",
  202. Host: targetAddress,
  203. })
  204. s := &tsnet.Server{
  205. Hostname: "tsnet-services-demo",
  206. }
  207. defer s.Close()
  208. ln, err := s.ListenService("svc:my-service", tsnet.ServiceModeHTTP{
  209. HTTPS: true,
  210. Port: 443,
  211. })
  212. if err != nil {
  213. log.Fatal(err)
  214. }
  215. defer ln.Close()
  216. log.Printf("Listening on https://%v\n", ln.FQDN)
  217. log.Fatal(http.Serve(ln, reverseProxy))
  218. }