PubliraGitHub

이 페이지는 최신 릴리스가 아닌 v0.1 버전을 설명합니다. 최신 릴리스는 v0.3 문서를 참고하세요.

이 페이지는 아직 한국어로 번역되지 않아 영어로 표시됩니다.

Installing

게시 업데이트

This page takes an install from nothing to a tenant console its first administrator signs in to. It follows the order the steps have to run in and explains what each one decides; the full list of variables each process reads, and every flag of publiractl, stay in the reference linked from each step.

It describes the smallest install, the one in the Overview: web-storefront, web-admin, publira server, and publira worker, managed from publiractl. Turning on the optional processes at the end adds the HTML mail and the Platform Console.

Before you start

Every release publishes its images to the GitHub Container Registry as ghcr.io/publira/<name>:<tag>, under the release's version, which is its Git tag without the v, such as 0.1.0 for v0.1.0: publira, publiractl, web-storefront, and web-admin, plus web-platform and email-renderer for the optional processes. They are public, so your hosts pull them without signing in, and nothing has to be built. Each one is published for linux/amd64 and linux/arm64; a host on any other platform finds no image to pull. The examples here name them ghcr.io/publira/<name>:<tag>; write the version of the release you are installing in place of <tag>. Releases says how the tags are numbered.

An install that changes the code, or runs on another platform, builds its own images instead, from the image build instructions at the commit it runs, pushes them where its hosts pull from, and names them in place of the published ones throughout.

Every publiractl step runs the publiractl image of the release you are installing. It carries the migrations and the role definitions of that release, so an image from another release would apply a schema the processes do not expect.

To run the whole install on one host, the Compose file in the repository provisions the services and wires the variables for you, as Docker Compose describes. The steps below are still what it runs.

Provision the services

Create these before the first step. Publira creates everything inside them, so each one starts empty.

  • A PostgreSQL database, and a superuser login on it. Only publiractl db migrate and publiractl db roles connect as the superuser: db roles creates the login roles and an event trigger, which only a superuser may do. No long-lived process ever uses this login.
  • A Valkey instance, or any server that speaks the Redis protocol. publira server, web-storefront, and web-admin share it for the image conversion cache, the rate limit counters, and the web apps' cache. A connection that carries a password has to use rediss://, with TLS: publira server refuses to start on a redis:// URL with a password in it.
  • An empty bucket in an S3-compatible object store, and a credential that can read and write it. Every uploaded image is kept there. publiractl setup saves the bucket and the credential, so the processes need nothing else to reach it. If the processes should use a credential from their environment instead, such as an instance role, leave the access key out at setup and give publira server, publira worker, and publiractl the AWS_* variables.
  • An SMTP account: its host, port, encryption, user name and password, and the address mail is sent from. Reader sign-up, password reset, and administrator invitations all go through it.
  • DNS for the tenant's domain and for admin.<domain>, both pointing at the reverse proxy. The first serves the tenant's public site and the second its console. If the console belongs on another host name, choose it now: publiractl setup takes it as --admin-domain.

Generate the secrets

An install needs a handful of secrets that only you hold. Generate a fresh set for every environment, keep them in your secret store, and never reuse a value written in the repository: those are for local development and are public.

SecretGenerate it withSet onWhat it protects
The secret encryption keysk1:$(openssl rand -base64 32) as PUBLIRA_SECRET_ENCRYPTION_KEYS, and k1 as PUBLIRA_SECRET_ENCRYPTION_PRIMARY_KEY_IDpublira server, publira worker, publiractlEvery credential the install stores: the SMTP password, the object store's secret key, the search engine's password, the Web Push private key, and each tenant's payment, push, and sign-in credentials
The access token signing keyopenssl rand -base64 32 as PUBLIRA_AUTH_JWT_SECRETpublira serverEvery signed-in session. Whoever holds it can sign a token for any user and call every API as them
Each web app's session keyopenssl rand -base64 32 as that app's PUBLIRA_AUTH_SECRETweb-storefront and web-admin, one eachThe session cookie, which carries the user's access token. The two apps may share one, but need not
The cache revalidation tokenopenssl rand -hex 32publira server and publira worker as PUBLIRA_REVALIDATE_TOKEN, web-storefront and web-admin as PNCH_REVALIDATE_TOKENThe endpoint the servers call to drop a web app's cached pages after a change. Without it the servers send nothing, and the web apps keep serving what they cached before the change
The web service tokenopenssl rand -base64 32 as PUBLIRA_WEB_SERVICE_TOKENpublira server and web-adminThe reads the console makes as itself rather than as one of its staff, such as the catalog lists every staff member sees alike, so it can cache them once for all of them. web-admin does not start without it
One password per database roleopenssl rand -hex 32, six timespubliractl db roles, and the connection URL of the process that uses the roleThe database itself. A connection URL carries the password unescaped, so keep to URL-safe characters, as the hex output does

The encryption keys need the most care. publiractl setup seals the SMTP password and the object store's key with them, and publira server and publira worker unseal them with the keys they were given. A process given other keys cannot read what publiractl stored: the worker would fail to send mail, and the server to reach the object store. Lose the keys and every stored credential has to be entered again. To replace a key later without losing what it sealed, add the new key beside the old one rather than in its place, as Rotating the secret encryption keys describes.

The database roles

The processes never connect as the superuser. publiractl db roles creates six login roles, and each part of the install connects as the one that matches what it does:

RoleConnects forWhat it can reach
publira_publicpublira server, serving the public site and the mobile appThe rows of the tenant the request is for
publira_adminpublira server, serving the tenant consoleThe rows of the tenant the request is for
publira_platformpublira server, serving the Platform Console, and the publiractl commands that change platform settings, setup among themEvery tenant, and the platform's own settings
publira_outboxpublira worker, sending mail and push notifications and revalidating cachesEvery tenant, and the platform settings its mail needs
publira_tickerpublira worker, running the jobs that act the moment a scheduled time passes, such as publishing an episodeThe few tables those jobs touch
publira_content_statspublira worker and publiractl job, running the maintenance and aggregation jobsEvery tenant, and the platform settings those jobs read

The split is what keeps one tenant's data away from another's. The two roles that answer requests from readers and from a tenant's staff are bound by row-level security to the tenant a request names, so a defect in one of those paths cannot read another tenant's rows. The platform's own tables, which hold the operators' password hashes and the platform's mail credentials, are out of reach of every role but publira_platform and the narrow reads the others are granted back: the worker's roles read the settings their jobs and mail need, and the tenant console's role reads the few settings its requests apply, among them the address the platform's mail is sent from, but not the mail server, account, and password stored beside it. Each process therefore gets one connection URL per role it uses, and the deployment reference names which variable carries which.

Bring the install up

1. Apply the migrations

Run db migrate on the superuser connection. It creates the schema, and exits without changing anything when there is nothing to apply.

docker run --rm -e PUBLIRA_DB_URL ghcr.io/publira/publiractl:<tag> db migrate

PUBLIRA_DB_URL is the superuser connection, such as postgres://postgres:<password>@db.internal:5432/publira?sslmode=require.

2. Create the roles

Run db roles on the same connection, giving each role the password you generated for it. It grants on the tables the migrations created, which is why it runs second.

docker run --rm -e PUBLIRA_DB_URL -v /run/secrets:/run/secrets:ro ghcr.io/publira/publiractl:<tag> db roles \
  --public-password-file /run/secrets/publira-public-db-password \
  --admin-password-file /run/secrets/publira-admin-db-password \
  --platform-password-file /run/secrets/publira-platform-db-password \
  --outbox-password-file /run/secrets/publira-outbox-db-password \
  --ticker-password-file /run/secrets/publira-ticker-db-password \
  --content-stats-password-file /run/secrets/publira-content-stats-db-password

Running it again changes nothing but the passwords it is given, so it is also how a role's password is rotated later. The other ways to pass a password are in the publiractl reference.

3. Start the four processes

Start publira server, publira worker, web-storefront, and web-admin from the images of the same release — ghcr.io/publira/publira:<tag> for the first two, with worker as the container argument of the second, and ghcr.io/publira/web-storefront:<tag> and ghcr.io/publira/web-admin:<tag> — with the variables in the deployment reference. Each connection URL names its role and the password db roles gave it, such as postgres://publira_public:<password>@db.internal:5432/publira?sslmode=require for PUBLIRA_PUBLIC_DB_URL. Set every one of them: a connection URL left unset falls back to a development URL, not to another of your variables, and fails to sign in.

publira worker creates the tables of its job queue when it starts, so it needs no step of its own. publira server and publira worker each report one check per database login in GET /readyz, so a role whose password does not match is named there.

4. Set the install up

publiractl setup saves what the install needs to serve its first tenant and creates the tenant's first administrator:

  1. The platform's default locale, the time zone new tenants start on, and the currency a tenant sells in until its administrators choose one (USD unless you give another).
  2. The object store, after a connection test it has to pass.
  3. Optionally, the catalog search engine, which is the database itself unless you choose another.
  4. The SMTP settings, and a test message if you give an address for one.
  5. Optionally, Web Push.
  6. The tenant, on its domain.
  7. Its first administrator, with a password you type or one it generates.

It connects as publira_platform, and seals the credentials it saves with the encryption keys, so give it the same keys the processes run with:

docker run --rm -it \
  -e PUBLIRA_PLATFORM_DB_URL \
  -e PUBLIRA_SECRET_ENCRYPTION_KEYS -e PUBLIRA_SECRET_ENCRYPTION_PRIMARY_KEY_ID \
  ghcr.io/publira/publiractl:<tag> setup

On a terminal it asks for every value. The same run can be made unattended, from a CI job or an init container, with every value given as a flag; that form is in the publiractl reference. The links it prints are built on PUBLIRA_TENANT_URL_SCHEME, the scheme readers' browsers reach the tenant on, which is https unless set. It describes the public address, not how the proxy reaches the processes, so a plain HTTP hop behind the TLS terminator does not change it. Set it to http only when browsers really open the tenant over HTTP, and then on publiractl and the processes alike.

A run that stops halfway, because a connection test failed for instance, is finished by running it again: it keeps every step already saved and asks only for the rest.

The summary at the end names the tenant site and the tenant console, and prints the administrator's password when it generated one. That is the only place the generated password appears, so keep it before you close the terminal.

5. Put the reverse proxy in front

Route the two host names to the processes:

  • admin.<domain>, or the console host you chose, to web-admin.
  • The tenant's domain to web-storefront.
  • /api and /images on either host to the edge listener of publira server, except /api/v1, which belongs to the web app the host picked.

The proxy routes only the host names you list, and answers any other with a 404 of its own. The repository ships sample configurations for Traefik, nginx, and Caddy, which read the lists from environment variables: the tenant's domain goes in PUBLIRA_EDGE_SITE_HOSTS, and its console host in PUBLIRA_EDGE_ADMIN_HOSTS.

Terminate TLS for both host names at the proxy. Reverse proxy takes one of the samples to HTTPS for these host names.

6. Sign in

Open the tenant console URL the setup summary printed — https://admin.<domain>, or the console host you gave it with --admin-domain — and sign in with the administrator's email address and password. The tenant console opens on the tenant setup created, and from there its staff can be invited and the site configured. The tenant's public site answers at https://<domain>.

Turning on the optional processes

Either process can be added to an install that is already serving. Neither one keeps data of its own; turning one on is a matter of running it and restarting the processes whose variables change.

HTML mail with email-renderer

Without email-renderer, the worker sends every mail as plain text. Run it, and set PUBLIRA_EMAIL_RENDERER_URL on publira worker to its address on the private network, such as http://email-renderer:8080; from then on every mail carries an HTML part beside the same text. Once the variable is set, the renderer is part of sending mail: while it is down, the worker holds each mail and retries it rather than falling back to plain text.

The Platform Console with web-platform

web-platform is the Platform Console, where operators manage tenants and platform settings from a browser rather than from publiractl. To run it:

  • Generate a session key for it the way you did for the other web apps, and set it as its PUBLIRA_AUTH_SECRET, at least 32 bytes; without one no operator can sign in. Give it the same PUBLIRA_GRPC_URL, PUBLIRA_WEB_SERVICE_TOKEN, PNCH_REDIS_URL, and PNCH_REVALIDATE_TOKEN as web-admin.
  • Set PUBLIRA_WEB_PLATFORM_INTERNAL_URL on publira server and publira worker, so cache revalidation reaches it, and PUBLIRA_PLATFORM_APP_URL on publira worker, the address operators open it at, which the links in its mail are built from.
  • Choose a host name for it, such as platform.example.com, point it at the reverse proxy, and route it to web-platform: in the samples, by listing it in PUBLIRA_EDGE_PLATFORM_HOSTS.

Open it and create its first operator on the setup screen. That operator is separate from the tenant administrator publiractl setup created: the Platform Console has accounts of its own, and the screen is offered until the first one exists. The language chosen on that screen becomes the platform's default locale, replacing the one publiractl setup saved. The screen also asks for the default currency, starting on the one publiractl setup saved, so leaving it as it is keeps it. Every other setting stays, and publiractl keeps working beside the console.

Next steps

The full list of variables each process reads is in the deployment reference, and the optional ones in the READMEs of publira server and publira worker, web-storefront, web-admin, and web-platform. Every publiractl command is in the publiractl reference.

On every later release, Upgrading brings the install forward: the migrations and the roles first, with that release's publiractl image, and then its processes.