Skip to content
ONIWC
iwc 0.1.0

Deployment

An IWC application builds into one self-contained bundle and runs on the same iwc binary you develop with. One command, iwc deploy, puts it on cPanel hosting or on your own server. This page is the production workflow end to end; Tutorial 16 walks through it with a real app.

The workflow

Terminal
iwc validate                 # files + tests + production build + security audit
iwc deploy prod              # build, upload, check the live site

The first iwc deploy prod asks where the site will run and sets it up; every later run just deploys. prod is any name — staging, client-a — and each target is set up and saved separately.

Deploy with iwc deploy

text
IWC deploy Setting up deploy target "prod" for shop.
  Where will the site run?
    1) Shared hosting with cPanel — most web hosting plans; no SSH needed
    2) My own server or VPS (SSH) — IWC installs the service, web server and HTTPS
  Choose [1]:

The wizard asks only for what it doesn't know, says where to find each detail, and writes the target into package.iwc itself. Logins never go into the project.

Shared hosting with cPanel

You need your cPanel address, your cPanel username and an API token (cPanel → Security → Manage API Tokens → Create). IWC then lists the account's domains to choose from — or creates a subdomain or folder — and deploys through cPanel's own API. No SSH, nothing to install.

text
→ deploying 1.2.0 3f9c2a7e1b04c5d6 to public_html
  • uploading the package (9427 KB)
  • extracting r20261109141516-3f9c2a7e1b04c5d6 into public_html
✓ release 1.2.0 3f9c2a7e1b04c5d6 is in place (database and settings.env kept)
✓ https://example.com answers 200 and the app's health check is ok
  • The site runs as a CGI program: pages, sign-in, APIs, uploads and jobs all work. The database (SQLite in data/, or PostgreSQL through settings.env) is created on the first visit.
  • Every deploy keeps data/ and settings.env; a folder that already holds another site is listed first and its .htaccess kept as .htaccess.before-iwc.
  • The address and user are saved in ~/.iwc/deploy, the token encrypted in IWC's vault — on your computer only.

Your own server or VPS

Any Linux server with SSH and systemd. You give its address, SSH user and port; IWC shows the server's host-key fingerprint for you to compare before trusting it, installs your SSH key with one password login (typed into ssh's own prompt), and sets the server up on the first deploy:

Serviceiwc-<package>-<target> under systemd: starts at boot, restarts on failure, unprivileged, listening on 127.0.0.1
Web server and HTTPSAdded beside an existing nginx or Caddy (certificates through certbot or Caddy), or Caddy installed on a server with neither; configuration checked before it's loaded
ReleasesActivated atomically, only if their migrations succeed; the previous one keeps serving until then

Setting the server up needs root or passwordless sudo; deploying afterwards doesn't. Full details: Your own server.

After deploying

Terminal
iwc server status prod       # live release, stored releases, the public URL checked from here
iwc logs prod                # the live app's log
iwc rollback prod            # put the previous release back (or: iwc rollback prod <id>)
iwc deploy prod              # ship the next change

Rollback works on both kinds of target and keeps the database: servers keep the last 10 releases, cPanel hosting the last 5 (in ~/.iwc-releases, outside every web folder).

Without a terminal (CI)

Terminal
IWC_CPANEL_TOKEN=… iwc deploy prod --host example.com --user acct           # cPanel
iwc deploy prod --host deploy@203.0.113.10 --key ci_key --fingerprint SHA256:…  # own server

What a build contains

FileContents
dist/manifest.jsonThe compiled project, including your stylesheets
dist/assets/Your static files
dist/openapi.json, openapi.yamlOpenAPI 3.1 for every API
dist/migrations/sqlite.sql, postgres.sqlThe schema as SQL, for review
dist/release.jsonName, version, content hash, build time
dist/report.jsonWhat each route sends, against its size budget

Other ways to run it

iwc deploy covers most sites. These remain for setups it doesn't:

CommandBest for
Run it yourselfiwc start dist behind your own proxyContainers, platforms with their own process manager
Your own release agentiwc host on the server, a url target in package.iwcInfrastructure you supervise yourself
Upload by handiwc build --zip, upload and extract in File ManagerHosting without cPanel's API

Run it yourself

Terminal
scp -r dist server:/srv/app/
ssh server 'cd /srv/app && APP_DATABASE_URL=postgres://… iwc start dist --host 127.0.0.1 --port 8080 --trust-proxy loopback'

iwc start serves in production mode: no seed rows, simulated services refused, Secure cookies and HSTS. Behind a proxy, --trust-proxy makes rate limits and logs see each visitor rather than the proxy. --base /shop serves the app under a path prefix. Health check: GET /_iwc/health.

Your own release agent

Terminal
# server
IWC_DEPLOY_TOKEN=<32+ random characters> iwc host --dir /srv/iwc-host --port 8080 --trust-proxy loopback
package.iwc
{ "name": "shop", "version": "1.4.0", "iwc": 1, "deploy": { "prod": { "url": "https://deploy.example.com", "tokenEnv": "IWC_DEPLOY_TOKEN" } } }

iwc deploy prod, iwc logs prod, iwc rollback prod and iwc pull prod copy/ then work against it over HTTPS with the token.

Upload a zip by hand

Terminal
iwc build --zip --folder shop      # → shop.zip beside the project

Upload and extract in public_html, then open https://yourdomain.com/shop/. Background jobs run briefly after each response; add a cron job running iwc.cgi run-jobs for scheduled work. --arch arm64 targets ARM hosts. Full details: Shared hosting.

Production configuration

SettingHow
Databaseapp.iwc database.url: {"env": "NAME"}; set NAME to a postgres:// URL, or sqlite
SecretsEnvironment variables only. iwc secrets export writes development vault values for a server; .env files are never packaged
Encryption keyIWC_ENCRYPTION_KEY for encrypted fields; iwc migrate --reencrypt rotates it
Site addressapp.iwc seo.siteUrl for canonical links, sitemaps and absolute URLs
Secrets on your own serveriwc server env prod set KEY (asked without echo; restarts the app). On cPanel: settings.env in the site's folder
Plain HTTP for testing--secure=false or IWC_INSECURE=1 — never on the internet

Migrations in production

Every start plans migrations from the schemas. New tables, fields and indexes apply automatically; removed fields are left in place so data is kept; type changes and new required fields without defaults on non-empty tables are refused with an explanation. IWC refuses a database holding tables it did not create (IWC_ADOPT_DATABASE=1 to adopt one deliberately). On your own server, a release whose migrations fail is never activated. On cPanel hosting, migrations run on the first visit after a deploy; iwc rollback puts the previous code back.

Backups

Terminal
iwc backup dist --out /var/backups/app-$(date +%F).iwcbak.tar.gz --keep 14
iwc restore /var/backups/app-2026-11-09.iwcbak.tar.gz dist            # into an empty database
iwc restore /var/backups/app-2026-11-09.iwcbak.tar.gz dist --replace  # over current data

A backup is one .tar.gz with every table, the audit trail and uploaded files. Restores run in one transaction. Backups move between SQLite and PostgreSQL in either direction.

Native apps

Terminal
iwc build --android --release     # signed APK + AAB when IWC_ANDROID_KEYSTORE… are set
iwc build --ios --release         # device archive; App Store .ipa when platforms.ios.teamId is set

See Android & iOS apps.

Hosting on ONIWC

ONIWC's own hosting runs websites made with the Website Generator today. Deploying your own IWC applications to ONIWC-managed hosting is not available yet; the options above work on any server now.

Source: apps/marketing/content/docs/deployment.md