@ -220,6 +220,16 @@ func newServeV2Command(e *serveEnv, subcmd serveMode) *ffcli.Command {
LongHelp : "Remove all handlers configured for the specified service." ,
Exec : e . runServeClear ,
} ,
{
Name : "advertise" ,
ShortUsage : fmt . Sprintf ( "tailscale %s advertise <service>" , info . Name ) ,
ShortHelp : "Advertise this node as a service proxy to the tailnet" ,
LongHelp : "Advertise this node as a service proxy to the tailnet. This command is used\n" +
"to make the current node be considered as a service host for a service. This is\n" +
"useful to bring a service back after it has been drained. (i.e. after running \n" +
"`tailscale serve drain <service>`). This is not needed if you are using `tailscale serve` to initialize a service." ,
Exec : e . runServeAdvertise ,
} ,
} ,
}
}
@ -401,7 +411,7 @@ func (e *serveEnv) runServeCombined(subcmd serveMode) execFunc {
return err
}
if forService {
e . addServiceToPrefs ( ctx , svcName .String ( ) )
e . addServiceToPrefs ( ctx , svcName )
}
target := ""
if len ( args ) > 0 {
@ -442,16 +452,16 @@ func (e *serveEnv) runServeCombined(subcmd serveMode) execFunc {
}
}
func ( e * serveEnv ) addServiceToPrefs ( ctx context . Context , serviceName string ) error {
func ( e * serveEnv ) addServiceToPrefs ( ctx context . Context , serviceName tailcfg . ServiceName ) error {
prefs , err := e . lc . GetPrefs ( ctx )
if err != nil {
return fmt . Errorf ( "error getting prefs: %w" , err )
}
advertisedServices := prefs . AdvertiseServices
if slices . Contains ( advertisedServices , serviceName ) {
if slices . Contains ( advertisedServices , serviceName .String ( ) ) {
return nil // already advertised
}
advertisedServices = append ( advertisedServices , serviceName )
advertisedServices = append ( advertisedServices , serviceName .String ( ) )
_ , err = e . lc . EditPrefs ( ctx , & ipn . MaskedPrefs {
AdvertiseServicesSet : true ,
Prefs : ipn . Prefs {
@ -526,6 +536,21 @@ func (e *serveEnv) runServeClear(ctx context.Context, args []string) error {
return e . lc . SetServeConfig ( ctx , sc )
}
func ( e * serveEnv ) runServeAdvertise ( ctx context . Context , args [ ] string ) error {
if len ( args ) == 0 {
return fmt . Errorf ( "error: missing service name argument" )
}
if len ( args ) != 1 {
fmt . Fprintf ( Stderr , "error: invalid number of arguments\n\n" )
return errHelp
}
svc := tailcfg . ServiceName ( args [ 0 ] )
if err := svc . Validate ( ) ; err != nil {
return fmt . Errorf ( "invalid service name: %w" , err )
}
return e . addServiceToPrefs ( ctx , svc )
}
const backgroundExistsMsg = "background configuration already exists, use `tailscale %s --%s=%d off` to remove the existing configuration"
// validateConfig checks if the serve config is valid to serve the type wanted on the port.