| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package tsnet_test
- import (
- "flag"
- "fmt"
- "log"
- "net/http"
- "net/http/httputil"
- "net/url"
- "os"
- "path/filepath"
- "tailscale.com/tsnet"
- )
- // ExampleServer shows you how to construct a ready-to-use tsnet instance.
- func ExampleServer() {
- srv := new(tsnet.Server)
- if err := srv.Start(); err != nil {
- log.Fatalf("can't start tsnet server: %v", err)
- }
- defer srv.Close()
- }
- // ExampleServer_hostname shows you how to set a tsnet server's hostname.
- //
- // This setting lets you control the host name of your program on your
- // tailnet. By default this will be the name of your program (such as foo
- // for a program stored at /usr/local/bin/foo). You can also override this
- // by setting the Hostname field.
- func ExampleServer_hostname() {
- srv := &tsnet.Server{
- Hostname: "kirito",
- }
- // do something with srv
- _ = srv
- }
- // ExampleServer_dir shows you how to configure the persistent directory for
- // a tsnet application. This is where the Tailscale node information is stored
- // so that your application can reconnect to your tailnet when the application
- // is restarted.
- //
- // By default, tsnet will store data in your user configuration directory based
- // on the name of the binary. Note that this folder must already exist or tsnet
- // calls will fail.
- func ExampleServer_dir() {
- dir := filepath.Join("/data", "tsnet")
- if err := os.MkdirAll(dir, 0700); err != nil {
- log.Fatal(err)
- }
- srv := &tsnet.Server{
- Dir: dir,
- }
- // do something with srv
- _ = srv
- }
- // ExampleServer_multipleInstances shows you how to configure multiple instances
- // of tsnet per program. This allows you to have multiple Tailscale nodes in the
- // same process/container.
- func ExampleServer_multipleInstances() {
- baseDir := "/data"
- var servers []*tsnet.Server
- for _, hostname := range []string{"ichika", "nino", "miku", "yotsuba", "itsuki"} {
- os.MkdirAll(filepath.Join(baseDir, hostname), 0700)
- srv := &tsnet.Server{
- Hostname: hostname,
- AuthKey: os.Getenv("TS_AUTHKEY"),
- Ephemeral: true,
- Dir: filepath.Join(baseDir, hostname),
- }
- if err := srv.Start(); err != nil {
- log.Fatalf("can't start tsnet server: %v", err)
- }
- servers = append(servers, srv)
- }
- // When you're done, close the instances
- defer func() {
- for _, srv := range servers {
- srv.Close()
- }
- }()
- }
- // ExampleServer_ignoreLogsSometimes shows you how to ignore all of the log messages
- // written by a tsnet instance, but allows you to opt-into them if a command-line
- // flag is set.
- func ExampleServer_ignoreLogsSometimes() {
- tsnetVerbose := flag.Bool("tsnet-verbose", false, "if set, verbosely log tsnet information")
- hostname := flag.String("tsnet-hostname", "hikari", "hostname to use on the tailnet")
- srv := &tsnet.Server{
- Hostname: *hostname,
- }
- if *tsnetVerbose {
- srv.Logf = log.New(os.Stderr, fmt.Sprintf("[tsnet:%s] ", *hostname), log.LstdFlags).Printf
- }
- }
- // ExampleServer_HTTPClient shows you how to make HTTP requests over your tailnet.
- //
- // If you want to make outgoing HTTP connections to resources on your tailnet, use
- // the HTTP client that the tsnet.Server exposes.
- func ExampleServer_HTTPClient() {
- srv := &tsnet.Server{}
- cli := srv.HTTPClient()
- resp, err := cli.Get("https://hello.ts.net")
- if resp == nil {
- log.Fatal(err)
- }
- // do something with resp
- _ = resp
- }
- // ExampleServer_Start demonstrates the Start method, which should be called if
- // you need to explicitly start it. Note that the Start method is implicitly
- // called if needed.
- func ExampleServer_Start() {
- srv := new(tsnet.Server)
- if err := srv.Start(); err != nil {
- log.Fatal(err)
- }
- // Be sure to close the server instance at some point. It will stay open until
- // either the OS process ends or the server is explicitly closed.
- defer srv.Close()
- }
- // ExampleServer_Listen shows you how to create a TCP listener on your tailnet and
- // then makes an HTTP server on top of that.
- func ExampleServer_Listen() {
- srv := &tsnet.Server{
- Hostname: "tadaima",
- }
- ln, err := srv.Listen("tcp", ":80")
- if err != nil {
- log.Fatal(err)
- }
- log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
- })))
- }
- // ExampleServer_ListenTLS shows you how to create a TCP listener on your tailnet and
- // then makes an HTTPS server on top of that.
- func ExampleServer_ListenTLS() {
- srv := &tsnet.Server{
- Hostname: "aegis",
- }
- ln, err := srv.ListenTLS("tcp", ":443")
- if err != nil {
- log.Fatal(err)
- }
- log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
- })))
- }
- // ExampleServer_ListenFunnel shows you how to create an HTTPS service on both your tailnet
- // and the public internet via Funnel.
- func ExampleServer_ListenFunnel() {
- srv := &tsnet.Server{
- Hostname: "ophion",
- }
- ln, err := srv.ListenFunnel("tcp", ":443")
- if err != nil {
- log.Fatal(err)
- }
- log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
- })))
- }
- // ExampleServer_ListenFunnel_funnelOnly shows you how to create a funnel-only HTTPS service.
- func ExampleServer_ListenFunnel_funnelOnly() {
- srv := new(tsnet.Server)
- srv.Hostname = "ophion"
- ln, err := srv.ListenFunnel("tcp", ":443", tsnet.FunnelOnly())
- if err != nil {
- log.Fatal(err)
- }
- log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintln(w, "Hi there! Welcome to the tailnet!")
- })))
- }
- // ExampleServer_ListenService demonstrates how to advertise an HTTPS Service.
- func ExampleServer_ListenService() {
- s := &tsnet.Server{
- Hostname: "tsnet-services-demo",
- }
- defer s.Close()
- ln, err := s.ListenService("svc:my-service", tsnet.ServiceModeHTTP{
- HTTPS: true,
- Port: 443,
- })
- if err != nil {
- log.Fatal(err)
- }
- defer ln.Close()
- log.Printf("Listening on https://%v\n", ln.FQDN)
- log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintln(w, "<html><body><h1>Hello, tailnet!</h1>")
- })))
- }
- // ExampleServer_ListenService_reverseProxy demonstrates how to advertise a
- // Service targeting a reverse proxy. This is useful when the backing server is
- // external to the tsnet application.
- func ExampleServer_ListenService_reverseProxy() {
- // targetAddress represents the address of the backing server.
- const targetAddress = "1.2.3.4:80"
- // We will use a reverse proxy to direct traffic to the backing server.
- reverseProxy := httputil.NewSingleHostReverseProxy(&url.URL{
- Scheme: "http",
- Host: targetAddress,
- })
- s := &tsnet.Server{
- Hostname: "tsnet-services-demo",
- }
- defer s.Close()
- ln, err := s.ListenService("svc:my-service", tsnet.ServiceModeHTTP{
- HTTPS: true,
- Port: 443,
- })
- if err != nil {
- log.Fatal(err)
- }
- defer ln.Close()
- log.Printf("Listening on https://%v\n", ln.FQDN)
- log.Fatal(http.Serve(ln, reverseProxy))
- }
|