Skip to content

Commit

Permalink
Enhance User Experience (#53)
Browse files Browse the repository at this point in the history
* better README 
* now takes "--root" 
* fixed store location
  • Loading branch information
samyfodil committed Aug 8, 2023
1 parent 480df05 commit a7388ae
Show file tree
Hide file tree
Showing 15 changed files with 326 additions and 110 deletions.
187 changes: 186 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,189 @@
[![GoDoc](https://godoc.org/github.com/taubyte/tau?status.svg)](https://pkg.go.dev/github.com/taubyte/tau)
[![Discord](https://img.shields.io/discord/973677117722202152?color=%235865f2&label=discord)](https://discord.gg/taubyte)

`tau` is the implementation of a Taubyte Node. Documentation: [https://tau.how](https://tau.how).
`tau` is the mainstream implementation of a Taubyte Node. When interconnected, these nodes form a network that's cloud computing-ready, offering features such as:
- Serverless WebAssembly Functions
- Website/Frontend Hosting
- Object Storage
- K/V Database
- Pub-Sub Messaging

For detailed documentation, visit [https://tau.how](https://tau.how).

## Getting started

### Requirements

#### Hardware
The requirements for `tau` vary depending on the shape, but at a minimum, assuming an empty shape, it requires:

- 512MB of RAM
- 2GB of storage space

#### Operating system
While `tau` can be cross-compiled to various operating systems, for a quick and seamless deployment we recommend using a Linux distribution that employs SystemD.


#### Network requirements
Depending on the enabled protocols, `tau` will require certain network ports to be available and open:

- Three configurable TCP ports for peer-to-peer (P2P) communication
- Ports 80 and 443 for HTTP and HTTPS respectively
- Ports 53 and 953 for DNS, supporting both TCP and UDP


#### Freeing DNS Ports
DNS needs to be freed up for seer protocol to start properly. Follow these steps to adjust DNS settings:

1. Open `/etc/systemd/resolved.conf` with a text editor (nano, vim)
2. Set `DNS=1.1.1.1` and `DNSStubListener=no`
3. Run `systemctl restart systemd-resolved.service`
4. Run `ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf`


### Installation

#### From source
```bash
$ go install github.com/taubyte/tau
```

#### From binary
- Download the [latest release](https://github.com/taubyte/tau/releases)
- Place the binary in one of the `$PATH` directories
- Ensure it's executable (`chmod +x`)

### Filesystem Structure
We at Taubyte prioritize convention over configuration. Hence, we've pre-defined the filesystem structure and its location as follows:
```
/tb
├── bin
│   └── tau
├── cache
├── config
│   ├── <shape-1>.yaml
│   ├── <shape-2>.yaml
│   └── keys
│   ├── private.key
│   ├── public.pem
│   └── swarm.key
├── logs
├── plugins
└── storage
```

> Note: If you prefer a different location, use the --root option.
### Configuration
Configuration files for `tau` are located at `/tb/config/shape-name.yaml`. Here's an example:

```yaml
privatekey: CAESQJxQzCe/N/C8A5TIgrL9F0p5iG...KzYW9pygBCTJSuezIc6w/TT/unZKJ5mo=
swarmkey: keys/test_swarm.key
protocols: [patrick,substrate,tns,monkey,seer,auth]
p2p-listen: [/ip4/0.0.0.0/tcp/8100]
p2p-announce: [/ip4/127.0.0.1/tcp/8100]
ports:
main: 8100
lite: 8102
ipfs: 8104
location:
lat: 120
long: 21
http-listen: 0.0.0.0:443
network-url: example.com
domains:
key:
private: keys/test.key
services: ^[^.]+\.tau\.example\.com
generated: g.example.com
whitelist:
postfix: [test.com]
regex:
- '^[^.]+\.test\.example\.com'
```
### Running `tau`
Execute a `tau` node with:
```bash
tau start --shape shape-name
```
For an alternative root to `/tb`:
```bash
$ tau start --shape shape-name --root path-to-root
```

### Systemd Configuration
To ensure that `tau` runs as a service and starts automatically upon system boot, you can set it up as a `systemd` service.

1. Create a new service file:
```bash
$ sudo nano /etc/systemd/system/tau.service
```

2. Add the following content to the file:
```plaintext
[Unit]
Description=Taubyte Node Service
After=network.target
[Service]
ExecStart=/path/to/tau/bin tau start --shape shape-name --root path-to-root
User=username
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
Replace `/path/to/tau/bin` with the actual path to your `tau` binary and `username` with the name of the user running `tau`.

3. Enable and start the service:
```bash
$ sudo systemctl enable tau
$ sudo systemctl start tau
```

To check the status:
```bash
$ sudo systemctl status tau
```

This ensures `tau` runs consistently, even after system reboots.

### Setting up DNS for your network
Next, set up DNS records for your seer, generated domain, and service URLs, all with a 1-minute TTL.

### Seer
For each host running seer, add an `A Record`.
Host: seer -> Value: 127.0.0.1

### Generated URL
Point your generated domain to your seers by adding a `NS Record`.
If `g.example.com` is your generated domain URL, the record would be:
Host: `g` -> Value: `seer.example.com`

### Service URL
Add a `NS Record` which by default should be your URL prefixed with tau.
This record will also point to your seers.
For `example.com` the record will be: `tau` -> `seer.example.com`

### Connecting to the network
It may take a few minutes for the DNS to recognize your changes. The best way to check is to perform a dig on your network's seer fqdn Like so:
```bash
$ dig a seer.tau.example.com
```
> replace `example.com` with your respective domain.

Then, on a client machine:

#### tau-cli
1. Get the `tau` cli if you don't have it already. Check [github.com/taubyte/tau-cli](https://github.com/taubyte/tau-cli).
2. Run `tau login`
3. Then `tau select network`
4. Choose `Remote` then type your network's domain

#### Web console
1. Go to [Taubyte Web Console](https://console.taubyte.com)
2. Fill in your email and select 'Custom' in the network selector
3. Enter the network's domain and hit the checkmark
4. Login
9 changes: 5 additions & 4 deletions cli/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/taubyte/tau/cli/node"
"github.com/taubyte/tau/config"
"github.com/urfave/cli/v2"
)

Expand Down Expand Up @@ -36,12 +37,12 @@ func startShape() *cli.Command {
Aliases: []string{"s"},
},
&cli.PathFlag{
Name: "config",
Required: true,
Aliases: []string{"c"},
Name: "root",
DefaultText: config.DefaultRoot,
},
&cli.BoolFlag{
Name: "dev",
Name: "dev-mode",
Aliases: []string{"dev"},
},
},

Expand Down
120 changes: 67 additions & 53 deletions cli/app/parse_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"

"github.com/libp2p/go-libp2p/core/pnet"
"github.com/taubyte/tau/config"
Expand All @@ -15,70 +17,82 @@ import (
"gopkg.in/yaml.v2"
)

// Parse from yaml
func parseSourceConfig(ctx *cli.Context) (*config.Protocol, *config.Source, error) {
// Parse from yaml
if ctx.IsSet("config") {
var (
src = new(config.Source)
protocol = new(config.Protocol)
)

data, err := os.ReadFile(ctx.Path("config"))
if err != nil {
return nil, nil, fmt.Errorf("reading config file path `%s` failed with: %s", ctx.Path("config"), err)
}
root := ctx.Path("root")

err = yaml.Unmarshal(data, &src)
if err != nil {
return nil, nil, fmt.Errorf("yaml unmarshal failed with: %s", err)
}
if !filepath.IsAbs(root) {
return nil, nil, fmt.Errorf("root folder `%s` is not absolute", root)
}

err = validateKeys(src.Protocols, src.Domains.Key.Private, src.Domains.Key.Public)
if err != nil {
return nil, nil, err
}
configRoot := root + "/config"
configPath := path.Join(configRoot, ctx.String("shape")+".yaml")

// Assign basics
protocol.Shape = ctx.String("shape")
protocol.P2PAnnounce = src.P2PAnnounce
protocol.P2PListen = src.P2PListen
protocol.Ports = src.Ports
protocol.Location = src.Location
protocol.NetworkUrl = src.NetworkUrl
protocol.GeneratedDomain = src.Domains.Generated
protocol.ServicesDomain = src.Domains.Services
protocol.HttpListen = src.HttpListen
protocol.PrivateKey = []byte(src.Privatekey)
protocol.Protocols = src.Protocols
protocol.Plugins = src.Plugins
protocol.Peers = src.Peers

protocol.DevMode = ctx.Bool("dev")

// Convert Keys
if len(src.Privatekey) > 0 {
base64Key, err := base64.StdEncoding.DecodeString(src.Privatekey)
if err != nil {
return nil, nil, fmt.Errorf("converting private key to base 64 failed with: %s", err)
}

protocol.PrivateKey = []byte(base64Key)
}
data, err := os.ReadFile(configPath)
if err != nil {
return nil, nil, fmt.Errorf("reading config file path `%s` failed with: %s", configPath, err)
}

protocol.SwarmKey, err = parseSwarmKey(src.Swarmkey)
if err != nil {
return nil, nil, err
}
src := &config.Source{}

err = yaml.Unmarshal(data, &src)
if err != nil {
return nil, nil, fmt.Errorf("yaml unmarshal failed with: %w", err)
}

src.Domains.Key.Private = path.Join(configRoot, src.Domains.Key.Private)
if src.Domains.Key.Public != "" {
src.Domains.Key.Public = path.Join(configRoot, src.Domains.Key.Public)
}
src.Swarmkey = path.Join(configRoot, src.Swarmkey)

err = validateKeys(src.Protocols, src.Domains.Key.Private, src.Domains.Key.Public)
if err != nil {
return nil, nil, err
}

protocol := &config.Protocol{
Root: root,
Shape: ctx.String("shape"),
P2PAnnounce: src.P2PAnnounce,
P2PListen: src.P2PListen,
Ports: src.Ports,
Location: src.Location,
NetworkUrl: src.NetworkUrl,
GeneratedDomain: src.Domains.Generated,
ServicesDomain: src.Domains.Services,
HttpListen: src.HttpListen,
PrivateKey: []byte(src.Privatekey),
Protocols: src.Protocols,
Plugins: src.Plugins,
Peers: src.Peers,
DevMode: ctx.Bool("dev-mode"),
}

protocol.DomainValidation.PrivateKey, protocol.DomainValidation.PublicKey, err = parseValidationKey(src.Domains.Key.Private, src.Domains.Key.Public)
// Convert Keys
if len(src.Privatekey) > 0 {
base64Key, err := base64.StdEncoding.DecodeString(src.Privatekey)
if err != nil {
return nil, nil, err
return nil, nil, fmt.Errorf("converting private key to base 64 failed with: %s", err)
}

return protocol, src, nil
protocol.PrivateKey = []byte(base64Key)
}

protocol.SwarmKey, err = parseSwarmKey(src.Swarmkey)
if err != nil {
return nil, nil, err
}

protocol.DomainValidation.PrivateKey, protocol.DomainValidation.PublicKey, err = parseValidationKey(
src.Domains.Key.Private,
src.Domains.Key.Public,
)
if err != nil {
return nil, nil, err
}

return nil, nil, errors.New("config path was not set")
return protocol, src, nil
}

func parseSwarmKey(filepath string) (pnet.PSK, error) {
Expand Down
Loading

0 comments on commit a7388ae

Please sign in to comment.