Production uses immutable release directories on the Windows host:
C:\inetpub\deployments\<site>\
releases\
<release-id>\
app\
core\
db\
public\ <- IIS physicalPath points here
scripts\
...
shared\
public.web.config <- machine-owned configuration
deployment-state.json
The complete repository is copied into each release. This is required because
public/Default.asp includes files above public/, including ../core and
../app. IIS exposes only <release>\public; sibling source, scripts, tests,
and database files are not web-root content.
Switching physicalPath from one release's public directory to another is the
atomic-ish cutover. The app pool is recycled after the switch. If the smoke test
fails, the installer restores the previous physical path and recycles again.
The script does not stop the site for the normal copy/staging phase.
The repository server is Gitea 1.11.4, which predates Gitea Actions. Treat
Gitea as the Git source only. Run scripts/deploy-iis-git.ps1 from one of:
The worker must have Tailscale reachability and OpenSSH key-based access to
webserver-1. No password, private key, database path, or connection string
belongs in this repository.
scripts/deploy-iis-git.ps1: controller/CI entry point. Validates branch and
worktree state, packages the full source tree, hashes it, transfers it with
scp, and invokes the host installer with ssh.scripts/install-iis-release.ps1: elevated host-side installer. Performs
preflight, preserves machine configuration, stages/releases, configures
Classic ASP parent paths, switches IIS, smoke tests, and rolls back.Both scripts target Windows PowerShell 5.1 syntax.
Complete these steps on webserver-1 before the first live deployment:
IIS-ASP / Web-ASP), and IIS URL Rewrite.public directory containing
its machine-specific web.config. On first deployment this file is copied
to shared\public.web.config and becomes the deployment-owned preserved
copy.Default deployment root:
C:\inetpub\deployments\<IIS site name>
Classic ASP parent paths are set explicitly at the site's location in
applicationHost.config by install-iis-release.ps1:
system.webServer/asp enableParentPaths = true
This is intentional. The ASP section is commonly locked against web.config
overrides, so the setting is applied at the host/site level rather than added to
repository public/web.config.
From a standalone checkout on a Windows worker, first validate without making a network connection:
.\scripts\deploy-iis-git.ps1 `
-SiteName 'ttasp' `
-RemoteTarget 'webserver-1' `
-ExpectedBranch 'master' `
-DryRun
-DryRun validates the local source, branch, dirty state, XML, package creation,
and argument construction. It prints remote operations but does not run ssh
or scp.
Next run a remote read-only preflight. This does connect to webserver-1, copies
only the installer to a temporary directory, and checks the existing site,
app pool, Classic ASP feature (when its feature cmdlet is available), URL
Rewrite module, and availability of a preservable web.config:
.\scripts\deploy-iis-git.ps1 `
-SiteName 'ttasp' `
-RemoteTarget 'webserver-1' `
-RemotePreflightOnly
For a normal deployment:
.\scripts\deploy-iis-git.ps1 `
-SiteName 'ttasp' `
-RemoteTarget 'webserver-1' `
-ExpectedBranch 'master' `
-BaseUrl 'http://127.0.0.1/'
Use a host header or HTTPS URL in -BaseUrl when the site's binding requires
one. If no URL is supplied, the installer uses the first HTTP binding's port on
127.0.0.1. -SkipSmokeTest is an explicit exception and should not be used in
unattended production CI.
The controller defaults to -ExpectedBranch master, matching the repository's
actual default branch. It refuses a different branch or dirty worktree. External CI should:
master;Use -AllowAnyBranch or -AllowDirty only for an intentional, reviewed manual
exception. If SourcePath is not itself a Git root, -AllowAnyBranch is
required because branch provenance cannot be proved.
A webhook receiver is not included. Gitea 1.11.4 can emit webhooks, but accepting and authenticating them safely is infrastructure-specific. Polling or a manually approved CI job is simpler unless an existing secured webhook runner is available.
The installer copies the current site's entire public\web.config to:
<DeployRoot>\shared\public.web.config
It then overwrites each staged release's repository version with that preserved file before cutover. This preserves all machine-specific values, especially:
ConnectionString and its Access Data Source path;Environment;ErrorLogPath and logging flags;The shared file is never automatically refreshed from repository content. To change production settings, edit the shared file under the host's normal change control, validate its XML, and deploy or roll back. Keep a protected backup. Do not commit production values.
Deployments do not run migrations by default. The sample db directory is
part of the complete release but the production connection string should point
to data outside the release tree.
-RunMigrations is available only as an explicit operator choice. Before using
it:
The old script's automatic legacy migrate_isbusiness_to_households.vbs path has
been removed from deployment. Run one-off data repair scripts only under a
separate reviewed procedure.
List release IDs on the host under <DeployRoot>\releases, or use the value in
deployment-state.json. Then run from the worker:
.\scripts\deploy-iis-git.ps1 `
-SiteName 'ttasp' `
-RemoteTarget 'webserver-1' `
-Rollback `
-RollbackTo '20260914-171500-a1b2c3d4e5f6' `
-BaseUrl 'http://127.0.0.1/'
Rollback refreshes the target release's public\web.config from the preserved
shared copy, switches physicalPath, recycles the app pool, and smoke tests. If
that smoke test fails, it restores the pre-rollback path.
The installer reports releases older than -KeepReleases as retention
candidates but does not delete them automatically. Delete only after confirming
they are neither current nor required for rollback and that backups exist.
<release-id>.staging.web.config XML are validated before promotion.physicalPath.Review Windows Event Log, IIS logs, app logs, the script transcript, and
deployment-state.json after any failure.
Powered by TurnKey Linux.