Skip to content
ONIWC
iwc 0.1.0

Tutorial 16: Build and deploy a production application

Objective: take the to-do app from Tutorials 8–10 to production: validate it, build it, run it on PostgreSQL behind HTTPS, deploy new releases safely, and back it up.

Prerequisites: Tutorial 9 (PostgreSQL). For option A, a cPanel hosting account or a Linux server/VPS with SSH; a Linux server or VM for options B and C; any hosting with a File Manager for option D.

Step 1: Validate

Terminal
iwc validate
Output
1/4 files and references
✓ 24 files · 7 screens · 7 apis · 2 schemas

2/4 tests
✓ 13 test(s) passed

3/4 production build
✓ tasks 1.0.0 builds (7 pages, 7 apis)

4/4 security
✓ no findings

✓ valid in 1.02s

validate stops at the first failing stage. Run it in CI on every change.

Step 2: Production configuration checklist

ItemWhere
Database URLTASKS_DATABASE_URL in the server environment (app.iwc names it)
Encryption key, if you use encrypted fieldsIWC_ENCRYPTION_KEY (iwc secrets set IWC_ENCRYPTION_KEY --generate, then iwc secrets export)
Provider credentialsthe {"env": …} names in .integration.iwc files
Simulated servicesreplaced with real providers — production refuses to start with them
Canonical addressapp.iwc seo.siteUrl, for sitemaps, canonical links and payment return URLs
Admin accountscreated through your data, with two-factor sign-in (auth.mfa)
Security auditiwc security --strict passes

.env files are never packaged or uploaded. Set secrets in the server's environment.

Step 3: Build

Terminal
iwc build --report

dist/ contains the compiled manifest.json, assets/, migrations/sqlite.sql and migrations/postgres.sql (for review), openapi.json/openapi.yaml, release.json and report.json. --report prints what each route sends against its size budget.

Terminal
iwc deploy prod

The first run asks where the app will run — shared hosting with cPanel or your own server/VPS — and walks you through it:

  • cPanel: your cPanel address, username and an API token (cPanel → Security → Manage API Tokens → Create). Pick one of the account's domains, or let IWC create a subdomain such as tasks.example.com.
  • Own server: its address, SSH user and port. Compare the host-key fingerprint it shows with your provider's console, then type the server password once so IWC can install your SSH key. The first deploy installs the service, the web server and HTTPS.

Set the database on the server: on cPanel, TASKS_DATABASE_URL=postgres://… in settings.env in the site's folder (File Manager); on your own server, iwc server env prod set TASKS_DATABASE_URL.

Output
→ deploying 1.0.0 3f9c2a7e1b04c5d6 to tasks.example.com
✓ release 1.0.0 3f9c2a7e1b04c5d6 is in place (database and settings.env kept)
✓ https://tasks.example.com answers 200 and the app's health check is ok

Check on it any time with iwc server status prod and iwc logs prod.

Step 4, option B: run it yourself

Terminal
export TASKS_DATABASE_URL="postgres://tasks:…@db.internal:5432/tasks"
iwc migrate --dry-run       # review
iwc start dist --host 127.0.0.1 --port 8080 --trust-proxy loopback

Production mode means: no seed rows, simulated services refused, Secure cookies and HSTS. Put a TLS proxy in front — for example Caddy:

Caddyfile
tasks.example.com {
  reverse_proxy 127.0.0.1:8080
}

Health check: GET /_iwc/health.

Step 4, option C: your own release agent

On the server, once:

Terminal
IWC_DEPLOY_TOKEN=<32+ random characters> TASKS_DATABASE_URL=postgres://… iwc host --dir /srv/iwc-host --port 8080

In package.iwc on your machine:

package.iwc
{
  "name": "tasks",
  "version": "1.0.0",
  "iwc": 1,
  "deploy": { "prod": { "url": "https://deploy.tasks.example.com", "tokenEnv": "IWC_DEPLOY_TOKEN" } }
}

Then, from your machine:

Terminal
iwc deploy prod        # build, upload; activated only if migrations succeed
iwc logs prod          # recent structured logs
iwc rollback prod      # reactivate the previous release
iwc pull prod copy/    # the live source and dist (never secrets)

A release whose migrations fail never goes live, and rollback is atomic.

Step 4, option D: upload a zip by hand

Terminal
iwc build --zip --folder tasks

On cPanel hosting, option A does all of this for you.

Upload tasks.zip in the File Manager, extract it in public_html, and open https://yourdomain.com/tasks/. The zip holds a CGI build of the runtime; the database is created on the first visit (SQLite in data/, or PostgreSQL via settings.env). For scheduled jobs on a quiet site, add a cron job: /home/<user>/public_html/tasks/iwc.cgi run-jobs.

Step 5: Back up

Terminal
iwc backup dist --out /var/backups/tasks-$(date +%F).iwcbak.tar.gz --keep 14

On PostgreSQL the backup is one consistent snapshot taken while the app runs. Restore with iwc restore <archive> dist (into an empty database) or --replace. A SQLite backup restores into PostgreSQL and the other way round.

Step 6: Ship a change

  1. Change files, iwc validate.
  2. Bump version in package.iwc.
  3. iwc deploy prod.
  4. If something is wrong, iwc rollback prod puts the previous release back — on your own server and on cPanel hosting. The database is kept.

New tables and fields migrate automatically; a destructive change is refused before anything is written, with the reason.

Troubleshooting

ProblemFix
iwc start refuses to startA required environment variable (database URL, provider credentials) is missing, or a simulated service is still configured.
cPanel refused the login (HTTP 401)Check the username; create a new API token. The next iwc deploy asks again.
THE SERVER'S HOST KEY HAS CHANGEDThe server was reinstalled, or the connection is intercepted. Confirm the new fingerprint on the provider's console first.
the deploy token (IWC_DEPLOY_TOKEN) must be at least 32 charactersOption C: use a longer random token on both ends.
Shared hosting shows "This site could not start"The reason is in data/logs/app.log; iwc.cgi and folders must be 755.
Cookies are not kept over plain HTTP in testingProduction cookies are Secure; test with --secure=false only on a trusted network.

More: Deployment, Security, Performance & budgets.

Source: apps/marketing/content/docs/tutorials/deploy.md