Skip to content
Closed
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ check: ## Run all validation checks (nix, format, lua).
@$(MAKE) lua-check
@echo "✅ All checks passed"


.PHONY: flake-check
flake-check: nix-flake-check ## Check Nix flake configuration (alias for nix-flake-check).

Expand Down
368 changes: 368 additions & 0 deletions docs/TAILSCALE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,368 @@
# Tailscale Setup and Usage Guide

This guide covers the setup, configuration, and usage of Tailscale VPN in this dotfiles repository.

## Overview

Tailscale is configured as a home-manager module that provides secure, private networking between your devices. The setup includes:

- Automatic service management via launchd (macOS) or systemd (Linux)
- Secure authentication key management using agenix
- Personal device connectivity configuration
- Network monitoring and management tools

## Prerequisites

- Tailscale account (free tier is sufficient for personal use)
- Admin access to your machine for service installation
- SSH key pair configured for agenix secrets management

## Initial Setup

### 1. Create a Tailscale Account

If you don't have a Tailscale account:

1. Visit [https://login.tailscale.com/start](https://login.tailscale.com/start)
2. Sign up with your preferred authentication method (Google, GitHub, Microsoft, etc.)
3. Complete the account setup process

### 2. Generate an Auth Key

1. Log in to the [Tailscale Admin Console](https://login.tailscale.com/admin)
2. Navigate to **Settings** → **Keys** in the left sidebar
3. Click **Generate auth key**
4. Configure the key settings:
- **Description**: `galactica-macbook` (or your device name)
- **Expiry**: `90 days` (recommended for personal use)
- **Ephemeral**: `No` (for persistent device)
- **Pre-approved**: `Yes` (for automatic connection)
- **Tags**: Leave empty for personal use
5. Click **Generate key**
6. **Important**: Copy the auth key immediately as it won't be shown again

### 3. Encrypt the Auth Key

Save your auth key to a temporary file and encrypt it:

```bash
# Save auth key to temporary file
echo "tskey-auth-xxxxxxxxxxxxxxxxxxxxxxxx" > /tmp/tailscale-auth.txt

# Encrypt the key for your host
make encrypt-key-galactica KEY_FILE=/tmp/tailscale-auth.txt

# Clean up the temporary file
rm /tmp/tailscale-auth.txt
```

## Configuration

### Module Options

The Tailscale module supports the following configuration options:

```nix
services.tailscale = {
enable = true; # Enable Tailscale service
acceptRoutes = false; # Accept advertised routes (default: false)
advertiseExitNode = false; # Advertise as exit node (default: false)
useExitNode = ""; # Exit node to use (default: none)
authKey = ""; # Auth key as string (alternative to authKeyFile)
authKeyFile = ""; # Path to auth key file (recommended)
extraUpArgs = [ # Additional arguments for tailscale up
"--reset"
"--accept-dns=false"
];
};
Comment on lines +66 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Documentation shows incorrect option path.

The example configuration uses services.tailscale, but the actual module defines options under modules.tailscale. Update the documentation to match the module's option path.

-services.tailscale = {
+modules.tailscale = {
   enable = true;                    # Enable Tailscale service
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
services.tailscale = {
enable = true; # Enable Tailscale service
acceptRoutes = false; # Accept advertised routes (default: false)
advertiseExitNode = false; # Advertise as exit node (default: false)
useExitNode = ""; # Exit node to use (default: none)
authKey = ""; # Auth key as string (alternative to authKeyFile)
authKeyFile = ""; # Path to auth key file (recommended)
extraUpArgs = [ # Additional arguments for tailscale up
"--reset"
"--accept-dns=false"
];
};
modules.tailscale = {
enable = true; # Enable Tailscale service
acceptRoutes = false; # Accept advertised routes (default: false)
advertiseExitNode = false; # Advertise as exit node (default: false)
useExitNode = ""; # Exit node to use (default: none)
authKey = ""; # Auth key as string (alternative to authKeyFile)
authKeyFile = ""; # Path to auth key file (recommended)
extraUpArgs = [ # Additional arguments for tailscale up
"--reset"
"--accept-dns=false"
];
};
🤖 Prompt for AI Agents
In docs/TAILSCALE.md around lines 66 to 77, the example config uses the wrong
option path `services.tailscale`; update the documentation to use the module
path `modules.tailscale` instead (replace all occurrences in that example and
any surrounding explanatory text), ensuring the option names and values remain
unchanged and any references elsewhere in the file are also adjusted to
`modules.tailscale`.

```
Comment on lines +66 to +78

Copilot AI Nov 29, 2025

Copy link

Choose a reason for hiding this comment

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

The documentation shows the module being configured as services.tailscale, but the actual module defines options under modules.tailscale (see line 16 in home-manager/modules/tailscale/default.nix). Update all documentation examples to use modules.tailscale instead of services.tailscale.

Copilot uses AI. Check for mistakes.

### Current Configuration

The galactica host is configured for personal device connectivity:

- **Authentication**: Uses encrypted auth key stored in agenix
- **Routes**: Does not accept or advertise routes
- **Exit Node**: Not configured as or using exit nodes
- **DNS**: Maintains local DNS settings
- **State**: Clean state on each restart

## Deployment

### Apply Configuration

```bash
# Build and switch to the new configuration
make switch-galactica

# Or for auto-detected host
make switch
```

### Verify Installation

```bash
# Check Tailscale status
tailscale status

# Check service status (macOS)
launchctl list | grep tailscale

# Check service status (Linux)
systemctl --user status tailscaled
```

## Usage

### Basic Commands

```bash
# Show connection status
tailscale status

# Show IP addresses
tailscale ip -4
tailscale ip -6

# List all devices in your network
tailscale status --self=false

# Ping another device
tailscale ping device-name

# Open Tailscale admin console
tailscale browse
```

### Network Access

Once connected, you can access other devices using:

- **Magic DNS**: `device-name.tailnet-name.ts.net`
- **Direct IP**: Use the IP shown in `tailscale status`

Example:
```bash
# Access another device via Magic DNS
ssh user@device-name.tailnet-name.ts.net

# Access via direct IP
ssh user@100.x.x.x
```

## Management

### Service Management

```bash
# Restart Tailscale service (macOS)
launchctl kickstart -k homebrew.mxcl.tailscaled

# Restart Tailscale service (Linux)
systemctl --user restart tailscaled

# Disconnect from Tailscale
tailscale down

# Reconnect to Tailscale
tailscale up
```

### Log Files

Log files are stored in `~/.local/share/tailscale/`:

- `tailscaled.log` - Main daemon logs
- `tailscaled.error.log` - Error logs
- `tailscale-up.log` - Connection logs
- `tailscale-up.error.log` - Connection error logs

## Troubleshooting

### Common Issues

#### 1. Authentication Fails

**Symptoms**: Service starts but shows "Not connected" in status

**Solutions**:
```bash
# Check if auth key is properly decrypted
ls -la /run/agenix/keys/tailscale-auth.age

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The command to check if the auth key is properly decrypted seems incorrect. The decrypted secret file managed by agenix will likely not have the .age extension. The command should probably check for the file without this extension.

Suggested change
ls -la /run/agenix/keys/tailscale-auth.age
ls -la /run/agenix/keys/tailscale-auth


# Manually authenticate
tailscale up --authkey=your-auth-key

# Check service logs
tail -f ~/.local/share/tailscale/tailscale-up.error.log
```

#### 2. Service Won't Start

**Symptoms**: Service fails to start or crashes immediately

**Solutions**:
```bash
# Check permissions on state directory
ls -la ~/.local/share/tailscale/

# Reset Tailscale state
rm -rf ~/.local/share/tailscale/tailscaled.state
make switch-galactica

# Check system logs (macOS)
log show --predicate 'process == "tailscaled"' --last 1h
```

#### 3. Network Connectivity Issues

**Symptoms**: Can't reach other devices or internet

**Solutions**:
```bash
# Check network status
tailscale netcheck

# Test connectivity to Tailscale servers
tailscale ping 100.100.100.100

# Reset network configuration
tailscale down
tailscale up --reset
```

### Debug Mode

Enable debug logging for troubleshooting:

```bash
# Stop the service
launchctl stop homebrew.mxcl.tailscaled

# Start manually with debug flags
tailscaled --debug --state=~/.local/share/tailscale/tailscaled.state
```

## Security Best Practices

### Auth Key Management

1. **Use non-ephemeral keys** for persistent devices
2. **Set reasonable expiry** (30-90 days for personal use)
3. **Rotate keys regularly** using the admin console
4. **Store keys securely** using agenix encryption

### Network Security

1. **Disable exit nodes** unless specifically needed
2. **Use ACLs** for access control in larger networks
3. **Monitor connections** regularly via admin console
4. **Keep software updated** with `make update`

### Privacy

1. **Magic DNS** is enabled by default for convenience
2. **Local DNS settings** are preserved (`--accept-dns=false`)
3. **No route acceptance** prevents unwanted network exposure

## Advanced Configuration

### Custom Tags and ACLs

For more complex setups, you can configure tags and ACLs:

```nix
services.tailscale = {
enable = true;
authKeyFile = config.age.secrets."keys/tailscale-auth.age".path;
extraUpArgs = [
"--reset"
"--accept-dns=false"
"--tag=tag:server"
];
};
```
Comment on lines +275 to +284

Copilot AI Nov 29, 2025

Copy link

Choose a reason for hiding this comment

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

Change services.tailscale to modules.tailscale to match the actual module definition.

Copilot uses AI. Check for mistakes.

### Exit Node Usage

To use an exit node (when needed):

```nix
services.tailscale = {
enable = true;
useExitNode = "exit-node-name";
# ... other options
};
```
Comment on lines +291 to +296

Copilot AI Nov 29, 2025

Copy link

Choose a reason for hiding this comment

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

Change services.tailscale to modules.tailscale to match the actual module definition.

Copilot uses AI. Check for mistakes.

### Multiple Networks

For users with multiple Tailscale networks:

```nix
services.tailscale = {
enable = true;
authKeyFile = config.age.secrets."keys/tailscale-auth.age".path;
extraUpArgs = [
"--reset"
"--accept-dns=false"
"--login-server=https://login.tailscale.com"
];
};
```
Comment on lines +303 to +312

Copilot AI Nov 29, 2025

Copy link

Choose a reason for hiding this comment

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

Change services.tailscale to modules.tailscale to match the actual module definition.

Copilot uses AI. Check for mistakes.

## Integration with Other Services

### SSH Configuration

Tailscale works seamlessly with SSH. Consider adding to your SSH config:

```sshconfig
Host *.ts.net
User your-username
IdentityFile ~/.ssh/id_ed25519
StrictHostKeyChecking no

@cubic-dev-ai cubic-dev-ai Bot Nov 29, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The SSH config example disables host key verification (StrictHostKeyChecking no), which exposes users to MITM attacks; keep host verification enabled instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/TAILSCALE.md, line 324:

<comment>The SSH config example disables host key verification (`StrictHostKeyChecking no`), which exposes users to MITM attacks; keep host verification enabled instead.</comment>

<file context>
@@ -0,0 +1,368 @@
+Host *.ts.net
+  User your-username
+  IdentityFile ~/.ssh/id_ed25519
+  StrictHostKeyChecking no
+  UserKnownHostsFile ~/.ssh/known_hosts.tailscale
+```
</file context>
Fix with Cubic

UserKnownHostsFile ~/.ssh/known_hosts.tailscale
```

### Development Tools

Many development tools work transparently with Tailscale:

- **Docker**: Containers can access Tailscale network
- **VS Code**: Remote SSH via Tailscale addresses
- **Git**: Access private repositories over Tailscale

## Maintenance

### Regular Tasks

1. **Monthly**: Check auth key expiry and rotate if needed
2. **Quarterly**: Review connected devices in admin console
3. **As needed**: Update configuration with `make switch-galactica`

### Updates

```bash
# Update entire dotfiles (includes Tailscale updates)
make update

# Update only Tailscale package
nix flake update
make switch-galactica
```

## Support

- **Tailscale Documentation**: [https://tailscale.com/kb/](https://tailscale.com/kb/)
- **Tailscale Support**: [https://support.tailscale.com/](https://support.tailscale.com/)
- **Community**: [https://github.com/tailscale/tailscale/discussions](https://github.com/tailscale/tailscale/discussions)

## File Locations

- **Module**: `home-manager/modules/tailscale/default.nix`
- **Configuration**: `named-hosts/galactica/default.nix`
- **Secrets**: `named-hosts/galactica/secrets.nix`
- **Auth Key**: `named-hosts/galactica/keys/tailscale-auth.age` (encrypted)
- **State**: `~/.local/share/tailscale/`
- **Logs**: `~/.local/share/tailscale/*.log`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This line duplicates information about log file locations, which is already detailed in the "Log Files" section (lines 173-178). You can remove this line to keep the documentation concise and avoid redundancy.

1 change: 1 addition & 0 deletions home-manager/modules/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[
./npm-globals
./tailscale
./yek
]
Loading
Loading