[Tutorial] Run your own satellite (part 13) - Satellite console

The Satellite Console is the web-based customer portal of the satellite, for customer to sign up and log into satellite dashboard.

Minimum Useful Console Command

./satellite-modular console \
--identity-dir ./id/satellite/ \
--database-options.url "cockroach://my_role:123456@rendezvous.example.com:26257/my_database?sslmode=verify-full&sslrootcert=ca.crt" \
--metainfo.database-url "cockroach://my_role:123456@rendezvous.example.com:26257/my_metainfo_database?sslmode=verify-full&sslrootcert=ca.crt" \
--live-accounting.storage-backend redis://127.0.0.1:6379 \
--mail.template-path=./emails \
--mail.from "no-reply@localhost" \
--console.auth-token-secret "4G3G17lzZvvZ5/v3kMQ/+7fmlTFQRQVWwTJBiaRbdU0=" \ # not a real key
--key-management.provider local \
--key-management.key-infos "1:master_key_1,2524231573" \
--key-management.default-master-key=1 \
--console.static-dir=./ \
--console.csrf-protection-enabled=true

--mail.template-path: similar with admin service, point path to directory from storj/web/satellite/static/emails at main · storj/storj · GitHub. Note that, this copy and paste operation need to be done on every deployment in case emails changed.

--console.auth-token-secret: generate this key with this command openssl rand -base64 32

Master Key:

When customer using managed project in storj, they don’t hold the secret key, you are the one holding their key for them, but we are also not storing plain secret key in our database.

StorJ using a master key to encrypt and store the encrypted version of customer secret key (the same master key used for all customers). To generate a master key: openssl rand 32 > master_key_1

And calculate crc32c (Castagnoli) of the key with this script:

import crcmod
data = open('master_key_1', 'rb').read()
crc32c = crcmod.predefined.mkCrcFun('crc-32c')
print(crc32c(data))

--key-management.key-infos: semicolon-separated key-id:version,checksum. With ‘gsm’ provider, version is the resource name. With ‘local’, it is the file path. Checksum is the integer crc32c checksum of the key data (eg: 1:master_key_1,2524231573;2:master_key_2,4524233543).

--key-management.default-master-key: it is the key-id in --key-management.key-infos

--console.static-dir: need two directories, static-dir is the parent of both static and dist dir, static dir from storj/web/satellite/static at 0adb45503fd3315cb9f4e06ee39cc5774625e8d5 · storj/storj · GitHub and dist dir from storj/web/satellite at 0adb45503fd3315cb9f4e06ee39cc5774625e8d5 · storj/storj · GitHub (generate by npm run build and npm run wasm).

To make satellite open to public registration, you also need --console.open-registration-enabled, if the satellite is invite-only then remember to config --console.auth-token.


The default port for console is 10100, if you want to split between back-end server and front-end endpoints, in that case see (./satellite-modular console -h | grep frontend).

Trademark Material

Unlike admin service where only you could see it, console could be seen by your customers, it is important that you fix all trademark material in console service.

As I understand so far, you can mention storj as the underlying technology but have to make clear that you are not affiliated with or endorsed by StorJ in any shape or form.

Have a look at this: ./satellite-modular console -h | grep '\-\-console' | grep storj, where you could fix some of it.

Here a screenshot of login console:

Also, this is not taking into account email yet, need to register an email service provider to run a production sat (see config at ./satellite-modular console -h | grep mail).

Good luck and see you in part 14.

I really enjoy the work you’re putting into documenting your progress. I hope you reach a time, where you can get real data on the network :slight_smile:

Perhaps @stefanbenten can help you out with some things.

Thank you! The tutor satellite is already up, but there are some works left before asking anyone to see it:

  1. Fix trademark material (in both email and console).
  2. Testing if email sending is really work and some unknown unknowns work.

Of course, I’ll documenting how to do it a long the way, so it might take few days more.

Also this is an incomplete sat, important service like ranged-loop is not configured (don’t know how to), research and tutorial will continue after I introduce the sat.

Hi @Alexey, it look like there is a different in Storj and self-hosted satellite:

# https://github.com/storj/storj/blob/753d3c96b739b3d71ef652062cba0a2dfbd735d5/web/satellite/src/components/CreateProjectForm.vue#L133
const showEncryptionDropdown = computed(() =>
    configStore.isDefaultBrand && satelliteManagedEncryptionEnabled.value && !configStore.state.config.hideProjectEncryptionOptions,
);

I can’t set my brand to Storj - that would be trademark violation, but it hardcode to check only show option self-managed and automatic (satellite managed) if the brand is Storj (is that what isDefaultBrand mean?).

I can enable satellite with --console.satellite-managed-encryption-enabled, but then every project create will be satellite managed, there is no option to choose for user of self-hosted satellite?

I don’t know, so asked the team.

Hi there,

I’ve a backup plan: hijack the frontend framework and change default brand name to the satellite own brand, and search and replace all storj link reference to Storj brand.

We could use something like ast-grep and maintaining our own patches.

Truth is, I look at isDefaultBrand and realize, this frontend is for Storj, whitelabel support is not there yet.

I think this is our best option for now, let me know if there are better way, thanks!

In storj current source code, there are 3 ways for you to run a satellite:

  • run as default (StorJ).
  • run the whole satellite as a single white label satellite.
  • run satellite as multi tenant white label satellite (aka: satellite as a service).

But this guide will be focus on the 4th option, a Frankenstein satellite between the first and second option (the reason stated above).

Most of satellite-modular configuration can be config via command line flags, for example:

--console.partnered-satellites
--console.satellite-name
--console.satellite-operator
--console.general-request-url
--console.project-limits-increase-request-url
--console.linksharing-url
--console.public-linksharing-url
--console.optional-signup-success-url
--console.external-compute-url
--console.captcha
...

Also, don’t be intimidate, my experience set up satellite so far: just set up your satellite first then see something is not to your expectation, then reseach how to fix that, don’t fix everything from the get go.


However, there are some config that can’t be set via this flag system, it is when you see noflag in config, for example:

# https://github.com/storj/storj/blob/6499657371f4360dc267a88ef14fa3cfb1fc616f/satellite/console/config.go#L87
SingleWhiteLabel SingleWhiteLabelConfig `noflag:"true"`

Very few config have noflag, and SingleWhiteLabel is all that matter, see example

// https://github.com/storj/storj/blob/6499657371f4360dc267a88ef14fa3cfb1fc616f/satellite/console/config.go#L606-L621

// single-brand deployments. When enabled (Name is set), the satellite uses
// custom branding instead of the default Storj branding.
//
// This is configured directly in YAML without CLI flag support.
// Example YAML:
//
//	console.single-white-label:
//	  name: "MyBrand"
//	  tenant-id: "my-tenant"
//	  logo-urls:
//	    full-light: "https://..."
//	    full-dark: "https://..."
//	  colors:
//	    primary-light: "#FF0000"
//	  support-url: "https://support.mybrand.com"

This yaml configuration will be put by you inside a file name config.yaml, and set via flag --config-dir, for now, these are configurable via config.yaml:

// https://github.com/storj/storj/blob/6499657371f4360dc267a88ef14fa3cfb1fc616f/satellite/console/config.go#L569-L595

// WhiteLabelConfig contains white-label configuration.
type WhiteLabelConfig struct {
	TenantID            string            `yaml:"tenant-id,omitempty"`
	HostName            string            `yaml:"host-name,omitempty"`
	ExternalAddress     string            `yaml:"external-address,omitempty"`
	Name                string            `yaml:"name,omitempty"`
	LogoURLs            map[string]string `yaml:"logo-urls,omitempty"`
	FaviconURLs         map[string]string `yaml:"favicon-urls,omitempty"`
	Colors              map[string]string `yaml:"colors,omitempty"`
	SupportURL          string            `yaml:"support-url,omitempty"`
	DocsURL             string            `yaml:"docs-url,omitempty"`
	HomepageURL         string            `yaml:"homepage-url,omitempty"`
	GetInTouchURL       string            `yaml:"get-in-touch-url,omitempty"`
	SourceCodeURL       string            `yaml:"source-code-url,omitempty"`
	SocialURL           string            `yaml:"social-url,omitempty"`
	BlogURL             string            `yaml:"blog-url,omitempty"`
	PrivacyPolicyURL    string            `yaml:"privacy-policy-url,omitempty"`
	TermsOfServiceURL   string            `yaml:"terms-of-service-url,omitempty"`
	TermsOfUseURL       string            `yaml:"terms-of-use-url,omitempty"`
	GatewayURL          string            `yaml:"gateway-url,omitempty"`
	CompanyName         string            `yaml:"company-name,omitempty"`
	AddressLine1        string            `yaml:"address-line1,omitempty"`
	AddressLine2        string            `yaml:"address-line2,omitempty"`
	AdminLogsEmail      string            `yaml:"admin-logs-email,omitempty"`
	AdminLogsWebhookURL string            `yaml:"admin-logs-webhook-url,omitempty"`
	SMTP                SMTPConfig        `yaml:"smtp,omitempty"`
	FreeTrialsEnabled   bool              `yaml:"free-trials-enabled,omitempty"`
}

Earlier I said Frankenstein satellite, let me introduce you to these home made patches, this is a system to patch code structurally GitHub - kocoten1992/patch_sat: some patch for storj satellite · GitHub.

Before buiding front end (in tutorial above, step npm run build and npm run wasm), run ./apply <path_to_root_storj_source_code_dir> to patch the satellite. So far, thing work for me, my tutor sat was able to use encryption option.

Ideally, you don’t read this section, read this if you encouter something unexpected and have no idea of the next step:

Content Security Policy

Will run into this when one forgot to config:

--console.frame-ancestors string           allow domains to embed the satellite in a frame, space separated (default "tardigrade.io storj.io")
--console.img-src-suffix string            additional values for Content Security Policy img-src, space separated (default "*.tardigradeshare.io *.storjshare.io *.storjsatelliteshare.io")
--console.connect-src-suffix string        additional values for Content Security Policy connect-src, space separated (default "*.tardigradeshare.io *.storjshare.io *.storjapi.io *.storjsatelliteshare.io")
--console.media-src-suffix string          additional values for Content Security Policy media-src, space separated (default "*.tardigradeshare.io *.storjshare.io *.storjsatelliteshare.io")
--console.object-src-suffix string         additional values for Content Security Policy object-src, space separated (default "*.tardigradeshare.io *.storjshare.io *.storjsatelliteshare.io")

How to know if you run into this? When press F12 to see what is happening and you saw your browser screaming CSP at you.

If your domain is for example: example.com, the content in all of those value should be: example.com *.example.com, if you have more domains, eg: example.com *.example.com example.net *.example.net.

Peer Classes are checking each other

--contact.external-address are different from --console.external-address, and you need both config for console, because some peer class are checking both ways, for example, console checking gateway and gateway also checking console.

--console.external-address='https://mysat.example.com/'
--contact.external-address=mysat.example.com:7777

Otherwise, the error are pretty obvious, your gateway will reject (disallow) your satellite.


Not an issue, but worth knowing when you want to limit new accounts (it will store in user setting in database, use sql to update it per user).

--console.usage-limits.bandwidth.paid
--console.usage-limits.project.paid
--console.usage-limits.storage.paid
# can ignore below, it less important
--console.usage-limits.segment.free
--console.usage-limits.segment.paid
--console.usage-limits.segment.nfr

Session duration

I notice inconsistency between Remember Me and manual override user session duration in user setting. Currently, Remember Me will set to exactly 7 days regardless of user config - is that a bug? You can change the default session duration via --console.session.duration.

Also, I just thought the button Remember Me kind of useless, of course I will remember my cyber traveller, so I remove that button and add option allow me to remember you forever.

You can run the satellite admin UI and use it for that.