Skip to content

feat: Add tunnel by default #4399

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Once installed, you can start a production deployment<sup>1</sup> with a single

```sh
# Automatically sets up an external access URL on *.try.coder.app
coder server --tunnel
coder server

# Requires a PostgreSQL instance and external access URL
coder server --postgres-url <url> --access-url <url>
Expand Down
1 change: 1 addition & 0 deletions cli/resetpassword_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestResetPassword(t *testing.T) {
serverCmd, cfg := clitest.New(t,
"server",
"--address", ":0",
"--access-url", "example.com",
"--postgres-url", connectionURL,
"--cache-dir", t.TempDir(),
)
Expand Down
48 changes: 21 additions & 27 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
tlsEnable bool
tlsKeyFiles []string
tlsMinVersion string
tunnel bool
traceEnable bool
secureAuthCookie bool
sshKeygenAlgorithmRaw string
Expand Down Expand Up @@ -243,26 +242,23 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
if tlsEnable {
localURL.Scheme = "https"
}
if accessURL == "" {
accessURL = localURL.String()
}

var (
ctxTunnel, closeTunnel = context.WithCancel(ctx)
devTunnel *devtunnel.Tunnel
devTunnelErr <-chan error
tunnel *devtunnel.Tunnel
tunnelErr <-chan error
)
defer closeTunnel()

// If we're attempting to tunnel in dev-mode, the access URL
// needs to be changed to use the tunnel.
if tunnel {
cmd.Printf("Opening tunnel so workspaces can connect to your deployment\n")
devTunnel, devTunnelErr, err = devtunnel.New(ctxTunnel, logger.Named("devtunnel"))
// If the access URL is empty, we attempt to run a reverse-proxy tunnel
// to make the initial setup really simple.
if accessURL == "" {
cmd.Printf("Opening tunnel so workspaces can connect to your deployment. For production scenarios, specify an external access URL\n")
tunnel, tunnelErr, err = devtunnel.New(ctxTunnel, logger.Named("devtunnel"))
if err != nil {
return xerrors.Errorf("create tunnel: %w", err)
}
accessURL = devTunnel.URL
accessURL = tunnel.URL
}

accessURLParsed, err := parseURL(ctx, accessURL)
Expand All @@ -288,11 +284,11 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
if isLocal {
reason = "isn't externally reachable"
}
cmd.Printf("%s The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL with:\n", cliui.Styles.Warn.Render("Warning:"), cliui.Styles.Field.Render(accessURLParsed.String()), reason)
cmd.Println(cliui.Styles.Code.Render(strings.Join(os.Args, " ") + " --tunnel"))
cmd.Printf("%s The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL by not specifying an access URL.\n", cliui.Styles.Warn.Render("Warning:"), cliui.Styles.Field.Render(accessURLParsed.String()), reason)
}

cmd.Printf("View the Web UI: %s\n", accessURLParsed.String())
// A newline is added before for visibility in terminal output.
cmd.Printf("\nView the Web UI: %s\n", accessURLParsed.String())

// Used for zero-trust instance identity with Google Cloud.
googleTokenValidator, err := idtoken.NewValidator(ctx, option.WithoutAuthentication())
Expand Down Expand Up @@ -472,7 +468,7 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
OIDCIssuerURL: oidcIssuerURL,
Prometheus: promEnabled,
STUN: len(derpServerSTUNAddrs) != 0,
Tunnel: tunnel,
Tunnel: tunnel != nil,
})
if err != nil {
return xerrors.Errorf("create telemetry reporter: %w", err)
Expand Down Expand Up @@ -569,17 +565,17 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
eg.Go(func() error {
// Make sure to close the tunnel listener if we exit so the
// errgroup doesn't wait forever!
if tunnel {
defer devTunnel.Listener.Close()
if tunnel != nil {
defer tunnel.Listener.Close()
}

return server.Serve(listener)
})
if tunnel {
if tunnel != nil {
eg.Go(func() error {
defer listener.Close()

return server.Serve(devTunnel.Listener)
return server.Serve(tunnel.Listener)
})
}
go func() {
Expand Down Expand Up @@ -624,7 +620,7 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Bold.Render(
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
))
case exitErr = <-devTunnelErr:
case exitErr = <-tunnelErr:
if exitErr == nil {
exitErr = xerrors.New("dev tunnel closed unexpectedly")
}
Expand All @@ -650,9 +646,9 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
// in-flight requests, give in-flight requests 5 seconds to
// complete.
cmd.Println("Shutting down API server...")
err = shutdownWithTimeout(server.Shutdown, 5*time.Second)
err = shutdownWithTimeout(server.Shutdown, 3*time.Second)
if err != nil {
cmd.Printf("API server shutdown took longer than 5s: %s", err)
cmd.Printf("API server shutdown took longer than 3s: %s\n", err)
} else {
cmd.Printf("Gracefully shut down API server\n")
}
Expand Down Expand Up @@ -694,10 +690,10 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
cmd.Println("Done waiting for WebSocket connections")

// Close tunnel after we no longer have in-flight connections.
if tunnel {
if tunnel != nil {
cmd.Println("Waiting for tunnel to close...")
closeTunnel()
<-devTunnelErr
<-tunnelErr
cmd.Println("Done waiting for tunnel")
}

Expand Down Expand Up @@ -855,8 +851,6 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, error))
"Paths to the private keys for each of the certificates. It requires a PEM-encoded file")
cliflag.StringVarP(root.Flags(), &tlsMinVersion, "tls-min-version", "", "CODER_TLS_MIN_VERSION", "tls12",
`Minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12" or "tls13"`)
cliflag.BoolVarP(root.Flags(), &tunnel, "tunnel", "", "CODER_TUNNEL", false,
"Workspaces must be able to reach the `access-url`. This overrides your access URL with a public access URL that tunnels your Coder deployment.")
cliflag.BoolVarP(root.Flags(), &traceEnable, "trace", "", "CODER_TRACE", false,
"Whether application tracing data is collected.")
cliflag.BoolVarP(root.Flags(), &secureAuthCookie, "secure-auth-cookie", "", "CODER_SECURE_AUTH_COOKIE", false,
Expand Down
14 changes: 14 additions & 0 deletions cli/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func TestServer(t *testing.T) {
root, cfg := clitest.New(t,
"server",
"--address", ":0",
"--access-url", "example.com",
"--postgres-url", connectionURL,
"--cache-dir", t.TempDir(),
)
Expand Down Expand Up @@ -87,6 +88,7 @@ func TestServer(t *testing.T) {
root, cfg := clitest.New(t,
"server",
"--address", ":0",
"--access-url", "example.com",
"--cache-dir", t.TempDir(),
)
pty := ptytest.New(t)
Expand Down Expand Up @@ -159,6 +161,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--access-url", "foobarbaz.mydomain",
"--cache-dir", t.TempDir(),
)
Expand Down Expand Up @@ -189,6 +192,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--access-url", "https://google.com",
"--cache-dir", t.TempDir(),
)
Expand Down Expand Up @@ -218,6 +222,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--tls-enable",
"--tls-min-version", "tls9",
"--cache-dir", t.TempDir(),
Expand All @@ -234,6 +239,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--tls-enable",
"--tls-client-auth", "something",
"--cache-dir", t.TempDir(),
Expand Down Expand Up @@ -290,6 +296,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--cache-dir", t.TempDir(),
}
args = append(args, c.args...)
Expand All @@ -310,6 +317,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--tls-enable",
"--tls-cert-file", certPath,
"--tls-key-file", keyPath,
Expand Down Expand Up @@ -349,6 +357,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--tls-enable",
"--tls-cert-file", cert1Path,
"--tls-key-file", key1Path,
Expand Down Expand Up @@ -432,6 +441,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--provisioner-daemons", "1",
"--cache-dir", t.TempDir(),
)
Expand All @@ -458,6 +468,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--trace=true",
"--cache-dir", t.TempDir(),
)
Expand Down Expand Up @@ -495,6 +506,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--telemetry",
"--telemetry-url", server.URL,
"--cache-dir", t.TempDir(),
Expand Down Expand Up @@ -525,6 +537,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--provisioner-daemons", "1",
"--prometheus-enable",
"--prometheus-address", ":"+strconv.Itoa(randomPort),
Expand Down Expand Up @@ -577,6 +590,7 @@ func TestServer(t *testing.T) {
"server",
"--in-memory",
"--address", ":0",
"--access-url", "example.com",
"--oauth2-github-client-id", "fake",
"--oauth2-github-client-secret", "fake",
"--oauth2-github-enterprise-base-url", fakeRedirect,
Expand Down
9 changes: 1 addition & 8 deletions coder.env
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# Coder must be reachable from an external URL
# for users and workspaces to connect.

# Option 1) Enable CODER_TUNNEL to generate a
# unique *. try.coder.com access URL
CODER_TUNNEL=false

# Option 2) Set an access URL
# Coder must be reachable from an external URL for users and workspaces to connect.
# e.g. https://coder.example.com
CODER_ACCESS_URL=

Expand Down
2 changes: 1 addition & 1 deletion coderd/authorize.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (api *API) checkAuthorization(rw http.ResponseWriter, r *http.Request) {
return
}

api.Logger.Warn(ctx, "check-auth",
api.Logger.Debug(ctx, "check-auth",
slog.F("my_id", httpmw.APIKey(r).UserID),
slog.F("got_id", auth.ID),
slog.F("name", auth.Username),
Expand Down
2 changes: 1 addition & 1 deletion coderd/csp.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (api *API) logReportCSPViolations(rw http.ResponseWriter, r *http.Request)
for k, v := range v.Report {
fields = append(fields, slog.F(k, v))
}
api.Logger.Warn(ctx, "csp violation", fields...)
api.Logger.Debug(ctx, "csp violation", fields...)

httpapi.Write(ctx, rw, http.StatusOK, "ok")
}
4 changes: 2 additions & 2 deletions coderd/workspaceagents.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func (api *API) dialWorkspaceAgentTailnet(r *http.Request, agentID uuid.UUID) (*
conn, err := tailnet.NewConn(&tailnet.Options{
Addresses: []netip.Prefix{netip.PrefixFrom(tailnet.IP(), 128)},
DERPMap: derpMap,
Logger: api.Logger.Named("tailnet").Leveled(slog.LevelDebug),
Logger: api.Logger.Named("tailnet"),
})
if err != nil {
return nil, xerrors.Errorf("create tailnet conn: %w", err)
Expand Down Expand Up @@ -453,7 +453,7 @@ func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request
// Ignore all trace spans after this.
ctx = trace.ContextWithSpan(ctx, tracing.NoopSpan)

api.Logger.Info(ctx, "accepting agent", slog.F("resource", resource), slog.F("agent", workspaceAgent))
api.Logger.Info(ctx, "accepting agent", slog.F("agent", workspaceAgent))

defer conn.Close(websocket.StatusNormalClosure, "")

Expand Down
3 changes: 0 additions & 3 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ services:
# that workspaces can reach. This cannot be localhost
# or 127.0.0.1 for non-Docker templates!
CODER_ACCESS_URL: "${CODER_ACCESS_URL}"
# Alternatively, you can enable CODER_TUNNEL for
# proof-of-concept deployments.
CODER_TUNNEL: "${CODER_TUNNEL:-false}"
# If the coder user does not have write permissions on
# the docker socket, you can uncomment the following
# lines and set the group ID to one that has write
Expand Down
10 changes: 5 additions & 5 deletions docs/admin/configure.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
Coder server's primary configuration is done via environment variables. For a full list
of the options, run `coder server --help` on the host.

## Tunnel

For proof-of-concept deployments, you can set `CODER_TUNNEL=true` to run Coder on a unique `*.try.coder.app` URL.
This is a quick way to allow users and workspaces outside your LAN to connect to Coder.

## Access URL

`CODER_ACCESS_URL` is required if you are not using the tunnel. Set this to the external URL
Expand All @@ -14,6 +9,11 @@ should not be localhost.

> Access URL should be a external IP address or domain with DNS records pointing to Coder.

### Tunnel

If an access URL is not specified, Coder will create
a publicly accessible URL to reverse proxy your deployment for simple setup.

## Wildcard access URL

`CODER_WILDCARD_ACCESS_URL` is necessary for [port forwarding](../networking/port-forwarding.md#dashboard)
Expand Down
Binary file removed docs/images/quickstart/aws/aws7.png
Binary file not shown.
Binary file removed docs/images/quickstart/azure/azure7.png
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/install/binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Coder publishes self-contained .zip and .tar.gz archives in [GitHub releases](ht

```sh
# Automatically sets up an external access URL on *.try.coder.app
coder server --tunnel
coder server

# Requires a PostgreSQL instance and external access URL
coder server --postgres-url <url> --access-url <url>
Expand Down
7 changes: 2 additions & 5 deletions docs/install/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ You can install and run Coder using the official Docker images published on [Git

Docker is required. See the [official installation documentation](https://docs.docker.com/install/).

## Run Coder with built-in database and tunnel (quick)
## Run Coder with the built-in database (quick)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's still mention we're using the tunnel here, both are configured here based on the lack of flags.


For proof-of-concept deployments, you can run a complete Coder instance with
the following command:
Expand All @@ -14,7 +14,6 @@ export CODER_DATA=$HOME/.config/coderv2-docker
export DOCKER_GROUP=$(getent group docker | cut -d: -f3)
mkdir -p $CODER_DATA
docker run --rm -it \
-e CODER_TUNNEL=true \
-v $CODER_DATA:/home/coder/.config \
-v /var/run/docker.sock:/var/run/docker.sock \
--group-add $DOCKER_GROUP \
Expand Down Expand Up @@ -68,7 +67,7 @@ an PostgreSQL container and volume.
```sh
cd coder

CODER_TUNNEL=true docker-compose up
docker-compose up
```

For production deployments, we recommend setting an [access URL](../admin/configure.md#access-url):
Expand All @@ -79,8 +78,6 @@ an PostgreSQL container and volume.
CODER_ACCESS_URL=https://coder.example.com docker-compose up
```

> Without `CODER_ACCESS_URL` or `CODER_TUNNEL` set, Coder will bind to `localhost:7080`. This will only work for Docker-based templates.

4. Visit the web ui via the configured url. You can add `/login` to the base url to create the first user via the ui.

5. Follow the on-screen instructions log in and create your first template and workspace
Expand Down
2 changes: 1 addition & 1 deletion docs/install/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
1. Run Coder as a system service.

```sh
# Set up an access URL or enable CODER_TUNNEL
# Optional) Set up an access URL
sudo vim /etc/coder.d/coder.env

# To systemd to start Coder now and on reboot
Expand Down
Loading