AlphaCOLLAB runs on GenesisL1 mainnet and has had no external audit. Use small amounts.Security notes

COLLAB

Installing COLLAB on a server

server/install.sh sets up a complete COLLAB site on a Debian or Ubuntu server with nginx. This is the complete reference for it: what to prepare, the commands, every option, what the installer prints, and the files, users and services it leaves behind. It sets up:

Part
Running a site
Version
COLLAB 2.2.0
Updated
Reading time
16 min
  • HTTPS. A Let's Encrypt certificate for every name, renewed by itself.
  • The names. The site at https://collab.genesisl1.com. dao.genesisl1.com, collab.descifi.org and dao.descifi.org answer 301 to the same path and query there.
  • The admin page at /admin: deploy the contracts from your wallet, publish them on this site, change the site's settings, watch its status.
  • The prerender job. It gives every DAO and token a page of its own for search engines and link previews, and keeps the logos, descriptions, token list and L1 price cached.

The site itself stays serverless. Visitors' browsers read the chain directly, and every page keeps working when the admin service or the prerender job is stopped. COLLAB 2.2 is an alpha: it has had no external audit (Security). Running a COLLAB site explains what the server does and does not do.

What you need

  • A server with Debian 11 or later, or Ubuntu 22.04 or later, root access, and ports 80 and 443 reachable from the internet.
  • The release archive, collab-2.2.0.tar.gz, and its .sha256 file.
  • For deploying the contracts: a browser wallet with some L1 for gas (section 4).

Before you install is the checklist: server, ports, DNS, firewall, an nginx that serves other sites, the main host and the RPC.

The installer adds what is missing: nginx, certbot, python3 with Pillow and pycryptodome, openssl and curl.

  • nginx may already serve other sites. The installer adds one file of its own and never touches theirs, nor the default site.
  • It refuses to go on when another site already answers for one of COLLAB's names (section 9).

1. DNS

Point each name at the server before you install: an A record with its IPv4 address and, when the server has IPv6, an AAAA record with that address.

NameRecordRole
collab.genesisl1.comA (and AAAA)the site
dao.genesisl1.comA (and AAAA)301 to the site
collab.descifi.orgA (and AAAA)301 to the site
dao.descifi.orgA (and AAAA)301 to the site

Check from your computer with dig +short collab.genesisl1.com, or from the server with getent ahosts collab.genesisl1.com, which is what the installer reads. If the names are on Cloudflare, set them to DNS only (grey cloud), at least until the certificate is issued.

The installer checks each name before asking for the certificate:

  • a name passes when its DNS points at an address of this server;
  • behind NAT or a proxy, it passes when a request through the name reaches this server.

A name that fails is left out of the certificate, with a warning. Run the installer again once its DNS is right. Before you install has the details.

2. Upload and install

From your computer, then on the server:

ssh root@SERVER mkdir -p /var/www/html    # a new server has no such folder before a web server
scp collab-2.2.0.tar.gz collab-2.2.0.tar.gz.sha256 root@SERVER:/var/www/html/
ssh root@SERVER
cd /var/www/html
sha256sum -c collab-2.2.0.tar.gz.sha256
tar xzf collab-2.2.0.tar.gz
sudo ./collab-2.2.0/server/install.sh --email you@example.org

--email is the contact address of the Let's Encrypt account; you may leave it out.

The extracted folder is only the installer's source:

  • The installer copies what the site needs to /var/www/collab/releases/2.2.0, and nothing depends on the folder afterwards.

  • /var/www/html is the root of nginx's default site, so its files can be fetched under http://SERVER/collab-2.2.0/ while it is there. It holds nothing secret.

  • Delete the folder and the archive once the install is done, or keep them until the next upgrade:

    sudo rm -rf /var/www/html/collab-2.2.0 /var/www/html/collab-2.2.0.tar.gz /var/www/html/collab-2.2.0.tar.gz.sha256

The installer prints what it does, step by step:

  1. Packages: installs only what is missing.
  2. Checking nginx: checks before changing anything, so a refused run leaves the server as it was.
    • nginx's configuration must pass its own test (nginx -T).
    • No other site may answer for COLLAB's names (wildcard names such as *.genesisl1.com are reported but not refused: nginx prefers COLLAB's exact names).
    • No program other than nginx may hold ports 80 or 443.
  3. Users and folders: creates the system users collab (the admin service) and collab-prerender (the prerender job) and the folders of section 7. The folders under shared/ are created so that a symbolic link or a folder of the wrong owner there is refused, never followed.
  4. Release: copies the release to /var/www/collab/releases/<version>, owned by root. Nothing is served from it yet.
  5. Settings: /etc/collab/collab.env, written on the first run with a new admin token and two secrets, and kept on every later run. Options you pass change only the values they name.
  6. Site configuration: config.js from the site settings and the published deployment, written as user collab. The content policy step writes the policy config.js needs into the new release's pages, and the helper /usr/local/sbin/collab is written. Until a deployment is published, every page says COLLAB is not deployed here yet.
  7. nginx: COLLAB's own file, /etc/nginx/sites-available/collab.conf, linked as sites-enabled/zz-collab.conf. Every change is checked with nginx -t; when nginx refuses it, the previous file comes back and nginx keeps running as before. Only then does /var/www/collab/current switch to the new release. When the release or its assets version changed, the old prerendered pages are removed first; releases older than the two before are deleted. Until there is a certificate, port 80 answers Let's Encrypt's challenges and a short "being set up" notice. Which site answers names nobody configured is explained in Domains, redirects and certificates.
  8. DNS and certificate: the check of section 1, then certbot certonly --webroot for one certificate named collab with every name that passed.
  9. nginx: HTTPS:
    • the site on 443 with HTTP/2 (before nginx 1.25.1, only when the other sites on port 443 use it already), HSTS, the security headers and caching;
    • one server that answers the other names with 301;
    • port 80 answers 301 to HTTPS on the main name for every name, and keeps the challenge path open for renewals.
  10. Services: the systemd units of section 7, enabled and started, and the admin service restarted. certbot's own timer renews the certificate, and the deploy hook the installer gives certbot, collab renewed, reloads nginx. Once HTTPS is on, the content policy step runs again (section 6). A prerender run is requested, and when ufw is active, ports 80 and 443 are allowed.
  11. Checking: the site and the admin service are asked through nginx, on the server itself.

It ends with a summary. This one is from the test sandbox (server/tests/sandbox_install.sh), which installs under other paths, on port 8443 and with a self-signed certificate; the admin token is masked here:

COLLAB 2.2.0 is installed. It is an alpha: the site says so at the top of every page.
Site:          https://collab.genesisl1.com:8443/
Redirected:    dao.genesisl1.com, collab.descifi.org, dao.descifi.org (301 to the site, path and query kept)
Admin page:    https://collab.genesisl1.com:8443/admin
Admin token:   ********************************    (any time: sudo /var/tmp/collab-sandbox.RNfwGK/root/bin/collab admin-token)
Certificate:   collab.genesisl1.com dao.genesisl1.com collab.descifi.org dao.descifi.org (self-signed, for testing)
Settings:      /var/tmp/collab-sandbox.RNfwGK/etc/collab/collab.env (the token and secrets; root:collab 0640)
Files:         /var/tmp/collab-sandbox.RNfwGK/root/current -> releases/2.2.0; /var/tmp/collab-sandbox.RNfwGK/root/shared (config.js, site.json, deployments, prerender, data)
Status, logs:  sudo /var/tmp/collab-sandbox.RNfwGK/root/bin/collab status | logs

Next: open the admin page, sign in with the token, deploy the contracts from your wallet (Deploy),
then Publish to this site. Until then every page says COLLAB is not deployed here yet.
The folder this ran from (/var/tmp/collab-sandbox.RNfwGK/src/collab-2.2.0) and its archive are no longer needed: delete them, or keep
them until the next upgrade (run the new release's server/install.sh the same way).

On a real server the helper is sudo collab admin-token, and the paths are /etc/collab and /var/www/collab. With Let's Encrypt the certificate line ends "(Let's Encrypt, renewed by certbot's timer)". Other lines that may appear:

  • Not covered: dao.descifi.org: point their DNS at this server, then run this again (the same command).
  • COLLAB 2.2.0 is installed, but not on HTTPS yet: see the warnings above. when the main name has no certificate yet.
  • This site is deployed: config.js names its contracts and was kept. in place of "Next: …" when a deployment is already published (an upgrade, or a second run).
  • This ran from an installed release (/var/www/collab/releases/2.2.0): keep that folder, it is part of the site. in place of the last two lines, when you ran the installer from an installed release (section 8).

Options

OptionWhat it does
--main HOSTthe site's address (default collab.genesisl1.com)
--alias HOSTanother name that answers 301 to it; repeat it for each name. The list replaces the default one, which is the other three of the four names above
--no-aliasesno other names
--email ADDRESScontact address of the Let's Encrypt account (optional)
--rpc URLthe RPC endpoint the prerender job reads (default: the site's own RPCs, in order); --rpc "" goes back to them
--admin-port Nthe admin service's port on 127.0.0.1 (default 8411)
-h, --helpthe installer's help text

These are for testing only (server/tests/sandbox_install.sh uses them):

OptionWhat it does
--self-signeda self-signed certificate instead of Let's Encrypt; browsers warn every visitor
--prefix DIRinstall under DIR instead of /var/www/collab, the helper as DIR/bin/collab
--etc DIRwhat goes to /etc goes to DIR instead: DIR/collab, DIR/nginx (its nginx.conf is the one tested and reloaded), DIR/systemd/system
--no-systemdstart no services: the units are written, and the commands to run are printed
--http-port NHTTP on N instead of 80
--https-port NHTTPS on N instead of 443

To make dao.genesisl1.com the main name on a first install, run the same command with --main dao.genesisl1.com. The aliases become the other three, and every redirect, canonical link and certificate follows.

Changing options later

The installer remembers --main, the aliases, --email, --rpc and the ports in /etc/collab/collab.env. A later run without them keeps them; an option you pass changes only what it names. --self-signed, --prefix, --etc and --no-systemd are not remembered: a run without --self-signed asks Let's Encrypt for a certificate.

Run the same installer again with the option, from the extracted folder or from the installed copy:

sudo /var/www/collab/current/server/install.sh --rpc https://rpc.example.org

Run from an installed release, the summary ends "This ran from an installed release (…): keep that folder, it is part of the site."

Two options need care:

  • --alias replaces the whole list of aliases. Name every alias you want to keep.
  • Switching the main host after the install keeps the remembered aliases, so the old main name is dropped unless you name it with --alias. See Domains, redirects and certificates.

3. The admin page

Open https://collab.genesisl1.com/admin and sign in with the admin token.

  • The installer prints the token; sudo collab admin-token shows it again.
  • sudo collab admin-token --new replaces it and ends every session signed in with the old one.

Sessions last 12 hours. Signing out ends the session at once, and stays effective when the admin service restarts. After 10 failed sign-ins in 10 minutes from one address, sign-in waits until the first of them is 10 minutes old.

The tabs:

  • Status: the release, the published deployment, the prerender job (last run, errors, warnings, its log), the certificate, the content policy, the server and config.js.
  • Deploy: deploys the protocol's contracts from your wallet. Any EIP-1193 browser wallet works (MetaMask, Rabby, Keplr in EVM mode): the page never asks for a key.
  • Publish: puts a deployment on this site, or takes it off.
  • Check: compares any deployment with this release, contract by contract.
  • Site settings: the alpha strip, an announcement, featured and hidden DAOs, verified and hidden tokens, search-engine texts, links, Google Analytics, RPC endpoints and the explorer.

Deploy and Check work without signing in. /deploy answers 301 to /admin/deploy. The admin page describes every tab.

4. Order of the first day

  1. Install (section 2) and open the admin page.
  2. Deploy the contracts on GenesisL1 from the Deploy tab: one transaction per contract, from your wallet. Let each transaction confirm before you reload the page. See Deploy the protocol from /admin.
  3. Publish to this site. The record is checked strictly:
    • chain 29, a COLLAB DAO v2.2 version;
    • every contract address present, non-zero and distinct, with a right EIP-55 checksum;
    • the integration lists checked as tools/write_web_config.py checks them.
  4. Wait for the first prerender (Status; a few seconds to minutes), then open the site, create a small test DAO and run one proposal through.
  5. Optionally: site settings, Google Analytics, and python3 /var/www/collab/current/deploy/check_site.py https://collab.genesisl1.com (Status, logs and the collab command).

To deploy with Foundry instead (Deploying COLLAB: reference, section 1), publish the record it writes from the Publish tab.

5. The deployment record and config.js

The server keeps one deployment for its chain (29), in /var/www/collab/shared/deployments/29.json.

  • Publishing another record replaces it.
  • Unpublish on the Publish tab (the admin API's {"record": null}) takes the site back to its undeployed mode.
  • The replaced file is kept in shared/history/, as every replaced config.js and site.json is (the newest 50 of each).

config.js is written only by tools/write_web_config.py: the admin service calls it, and so does the installer. It holds:

  • the record's addresses and integration lists;
  • "deployed";
  • the site settings as "site";
  • the RPC endpoints, explorer and analytics ID from the site settings;
  • the site's address.

The page caches never keep it: a change takes effect on the next page load. Publish, unpublish and check covers the operator's side, and Data formats the file itself.

6. Site settings and the content policy

Site settings are kept in shared/site.json and checked strictly. Unknown keys, control or invisible characters, URLs other than https, malformed slugs or addresses, and lists that are too long are all refused, naming the field. Site settings describes every field. Hiding changes nothing on chain or on other copies of COLLAB.

Some settings change the site's Content-Security-Policy: an analytics ID, or other RPC endpoints.

  • The policy is the <meta> tag of every page, and the same policy, with frame-ancestors, is nginx's header.
  • The admin service cannot change either, by design.
  • It drops a request file instead. collab-apply.path then starts collab-apply.service as root.

That service:

  • checks every value of config.js again, and trusts nothing the admin service wrote;
  • builds the policy from origins only, and refuses one with any character it never needs;
  • writes the policy into the release's pages and into COLLAB's own nginx file, and touches nothing else;
  • checks nginx with nginx -t and reloads it. When nginx refuses, it puts every file back and says why in Status (and in sudo collab logs);
  • does nothing when the policy is unchanged;
  • asks for a prerender run afterwards, so the prerendered pages carry the new policy too.

The installer runs the same step after every upgrade, so a new release gets the policy too. sudo collab apply runs it by hand.

7. Files, users and services

/var/www/collab/
  releases/<version>/   web/, tools/, server/, deploy/, docs/ of a release (root; only the policy step changes its pages)
  current -> releases/<version>
  shared/               collab, 0755
    config.js           the site's configuration (served at /config.js)
    site.json           the site settings
    deployments/29.json the published deployment record
    history/            the replaced versions (0750)
    status/             the content policy step, the certificate's status and the sign-in sessions (0750)
    jobs/               the prerender job's requests, status, log, lock and caches (collab-prerender, group collab, 2770)
    prerender/          the prerender job's pages, preview images and sitemap (collab-prerender)
    data/               its cache, served at /data/: logos, descriptions, tokens.json, price.json (collab-prerender)
  acme/                 Let's Encrypt's webroot
/etc/collab/            0751
  collab.env            settings, the admin token and two secrets (root:collab 0640)
  prerender.env         the same settings without the secrets, for the prerender job (0644)
  nginx-proxy.conf      the secret header nginx adds for the admin service (root 0600)
  tls/                  only with --self-signed: the test certificate
/etc/nginx/sites-available/collab.conf, sites-enabled/zz-collab.conf
/etc/letsencrypt/live/collab/   the certificate (certbot's)
/usr/local/sbin/collab  the helper
UnitWhat it does
collab-admin.servicethe admin API, user collab, on 127.0.0.1:8411
collab-prerender.serviceone prerender run, user collab-prerender
collab-prerender.timerthe prerender every 10 minutes
collab-prerender.patha prerender as soon as the admin page asks for one
collab-apply.path + collab-apply.servicethe content policy step, as root, on request
certbot.timercertificate renewal (certbot's own)

How the services are confined:

  • The admin service runs sandboxed by systemd: no privileges, a read-only system, no network beyond 127.0.0.1, and write access to shared/ only.
    • It accepts only requests that carry the secret header nginx adds.
    • Every state-changing request must be JSON, carry X-Collab-Admin: 1 and come from the site's own origin.
  • The prerender job has its own user and may write only prerender/, data/ and jobs/.
    • It cannot read the admin token or the secrets.
    • It needs outbound HTTPS to the RPC endpoints and to api.coingecko.com.
    • nginx never serves scripts, config.js or the admin page from its folders. A job that reads untrusted chain data, images included, can change neither the contracts the site uses nor its code.

The helper, sudo collab …:

Command
admin-token [--new]the admin token (a new one)
statusrelease, site, deployment, prerender, content policy, certificate, services
prerender [--request]run the prerender job now, in the foreground (or ask the service for a run)
logs [-f] [LINES]the log of the admin service, the prerender job and the policy step
applythe content policy step
renewedcertbot's deploy hook: reload nginx and note the new certificate

Status, logs and the collab command shows what each prints.

8. Upgrades, backups and moving

Upgrade. Upload and extract the new archive as in section 2, and run its installer:

cd /var/www/html && tar xzf collab-2.2.1.tar.gz && sudo ./collab-2.2.1/server/install.sh

Extract each archive where no folder of the same name is left. tar over an older collab-2.2.1/ keeps the files the new archive no longer has, and the installer copies them into the release with the rest, without checking them against SHA256SUMS. Delete such a folder first.

The settings, the token, the published deployment, the site settings and the certificate are kept, and the two previous releases stay in releases/.

Going back. Run the older release's own copy of the installer, never ln -sfn:

sudo /var/www/collab/releases/2.2.0/server/install.sh

Backups. Back up /etc/collab and shared/site.json, config.js, deployments/ and history/.

Upgrades, rollbacks and backups has the commands, what happens at each step, restoring and moving to another server.

9. Troubleshooting

What you seeWhat to do
"Another site on this nginx answers for a name COLLAB would take"That site's file is named. Remove the name from its server_name (and sudo nginx -t && sudo systemctl reload nginx), or install without it (--main, --alias, --no-aliases). Nothing was changed.
"Port 80 is used by another program" (or 443)Another web server (Apache, Caddy) holds the port. Stop or reconfigure it, then run the installer again.
A name "points at …, not at this server", or the certificate leaves names outFix the DNS record (section 1) and run the same command again; the certificate is extended. Port 80 must be reachable from the internet for Let's Encrypt.
certbot could not get the certificateThe installer shows certbot's last lines; /var/log/letsencrypt/letsencrypt.log has the rest. Fix the cause before trying again: Let's Encrypt allows only a few failed validations an hour.
The site answers "COLLAB is being set up" (503)There is no certificate for the main name yet (above).
The admin page says the admin service is not runningsudo systemctl status collab-admin, sudo collab logs.

The installer can always be run again: it repairs what is missing and keeps what is there. Troubleshooting covers these and the other cases, from the prerender's warnings to a refused content policy.

10. Testing the installer

sudo server/tests/sandbox_install.sh runs the installer in a sandbox without touching the system's nginx. It sets up:

  • a private nginx on ports 8088 and 8443, with another site on it;
  • a self-signed certificate;
  • the admin service as user collab.

Then it checks:

  • the refusal while another site claims a name;
  • nginx -t, the redirects, headers, caching, /data/ and the prerender overlay;
  • the admin API with its refusals and limits, and the content policy step;
  • deploy/check_site.py;
  • a second run that changes nothing, the same version again with other files, an upgrade, and a run from an installed release;
  • the Let's Encrypt path, with certbot and DNS stubbed: one name without DNS, the deploy hook, and a next run that keeps the certificate.

python3 -m unittest discover -s server/tests runs the unit tests of the admin service. See Testing.