Get started
In a few minutes you deploy a small shop, a JSON API over a Postgres database, and then branch it: a second, full copy of the app with its own copy of the data, at its own address.
You need Docker with docker compose on your machine, on Linux or macOS.
# 1. Install the CLI
curl -fsSL https://omniarc.eu/install.sh | sh
It puts omniarc in ~/.local/bin, with no sudo, and prints the line to add if that directory is not on your PATH.
# 2. Get a key
Create an account at dashboard.omniarc.eu. During the beta an account comes from an invite: the link in it creates the account. Open Keys, mint a key with the role admin (deploying needs it), and copy it: it is shown once. Then give it to the CLI:
export OMNIARC_KEY=<the key you copied>
That is the only setting. Every command finds OmniArc on its own.
# 3. Make the shop
The shop is two compose services: web, PostgREST answering HTTP on port 3000, and db, Postgres with a few products, customers and orders. Paste this into a terminal to create it in a new shop directory:
mkdir -p shop/db && cd shop
cat > docker-compose.yml <<'EOF'
# A small shop: Postgres holds the products, customers and orders, and
# PostgREST serves them as a JSON API on port 3000.
services:
web:
image: postgrest/postgrest:v12.2.12
environment:
PGRST_DB_URI: postgres://shop:${POSTGRES_PASSWORD:-shop}@db:5432/shop
PGRST_DB_SCHEMAS: public
PGRST_DB_ANON_ROLE: web_anon
PGRST_SERVER_PORT: 3000
ports: ["3000:3000"]
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
environment:
POSTGRES_USER: shop
POSTGRES_DB: shop
# Set a real one with `omniarc env set POSTGRES_PASSWORD`, which asks for it.
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-shop}
volumes:
- db-data:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shop -d shop"]
interval: 5s
timeout: 5s
retries: 10
volumes:
db-data:
EOF
cat > db/init.sql <<'EOF'
-- Runs once, when the database is first created.
create table products (
id serial primary key,
name text not null,
price_cents integer not null
);
create table customers (
id serial primary key,
email text not null
);
create table orders (
id serial primary key,
customer_id integer not null references customers,
product_id integer not null references products,
quantity integer not null default 1
);
insert into products (name, price_cents) values ('Mug', 1200), ('T-shirt', 2500), ('Poster', 900);
insert into customers (email) values ('ada@example.com'), ('alan@example.com');
insert into orders (customer_id, product_id, quantity) values (1, 1, 2), (2, 3, 1);
-- The API answers anonymous requests as web_anon, which can read the
-- catalogue and nothing else: customers and orders stay private.
create role web_anon nologin;
grant usage on schema public to web_anon;
grant select on products to web_anon;
grant web_anon to shop;
EOF
Nothing in it is written for OmniArc. It is an ordinary compose project, and docker compose up runs it on your machine too.
# 4. Write arc.yaml
arc.yaml sits next to the compose file and says what compose cannot. Let the CLI draft it from your compose file:
omniarc sync --write --arc shopguess: db: assumed `contains_pii: true`, `branch: false`, `kind: database`: branches start it empty; add anonymize rules or set contains_pii: false for test data to branch its data
guess: web: assumed `contains_pii: false`: it keeps nothing (no named volume, no writable bind inside the project, no database or cache image)
guess: edge: web port 3000, the only published HTTP-looking port
wrote ./arc.yaml
A service that keeps data is assumed to hold personal data, because a wrong guess the other way would copy real customers into every branch, and it starts empty in every branch until you say how to anonymize it. web keeps nothing of its own, so it holds none. Ask whether it is ready:
omniarc check
It is, and it would deploy as it is. But a branch of it would start with an empty database, which is not much of a copy. To branch db's data, say how to anonymize it: open arc.yaml and make it say this, the file in the panel:
arc: shop
edge: { service: web, port: 3000 }
resources: { cpu: "1", memory: 1Gi, disk: 5Gi }
services:
web:
kind: web-service
contains_pii: false
db:
kind: database
contains_pii: true
anonymize:
engine: postgres
database: shop
user: shop
rules:
- { table: customers, column: email, transform: fake-email }
web keeps no data of its own, so it holds no personal data. db holds customers' email addresses, and every branch gets made-up ones instead. The edge is the one service that answers the arc's public address. Run omniarc check again, and it ends with checks ok.
# 5. Deploy
omniarc deploy
The first deploy creates the arc. It uploads the project, builds and starts it, and follows it until every service is up:
created arc shop
...
revision 1 healthy
Every arc starts with one branch, production. Its public address is made within about five minutes of the first deploy:
omniarc arc branch url shop productionurl https://<hex>.arc.omniarc.eu (pending)
The address is ten random hex characters under arc.omniarc.eu. It says (pending) until its certificate is issued, (ready) after. If it answers that the branch has no public URL yet, ask again in a minute. Open the address with /products on the end, and the shop answers with its catalogue:
[{"id":1,"name":"Mug","price_cents":1200},
{"id":2,"name":"T-shirt","price_cents":2500},
{"id":3,"name":"Poster","price_cents":900}]
The customers and orders stay private: /customers answers permission denied, as init.sql asked.
# 6. Branch it
omniarc arc branch create shop production preview --wait-urlshop/production → shop/preview
anonymized db: 1 rule(s), 2 row(s)
url https://<hex>.arc.omniarc.eu (pending)
waiting for the URL to serve (up to 180 s)...
url https://<hex>.arc.omniarc.eu (ready)
It waits, up to three minutes, until the branch's own address serves. preview is the whole shop again: both services, a copy of the database, and that address. In its copy, the two customers' email addresses are made up. Open that address with /products on the end: same catalogue, separate data. Whatever you do to preview never touches production.
When you are done with it:
omniarc arc branch destroy shop preview# Next
- The model: arcs, branches and services, in one page.
- Write arc.yaml for your own compose project.
- Branches: a copy for every pull request.