Files
cloudron-box/src/views/domains.html

344 lines
21 KiB
HTML
Raw Normal View History

2018-01-22 13:01:38 -08:00
<div class="modal fade" id="domainConfigureModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" ng-show="domainConfigure.adding">Add Domain</h4>
<h4 class="modal-title" ng-hide="domainConfigure.adding">Configure {{ domainConfigure.domain.domain }}</h4>
</div>
<div class="modal-body">
<form name="domainConfigureForm" role="form" novalidate ng-submit="domainConfigure.submit()" autocomplete="off">
<fieldset>
<p class="has-error text-center" ng-show="domainConfigure.error">{{ domainConfigure.error }}</p>
<div class="form-group" ng-class="{ 'has-error': domainConfigureForm.newDomain.$invalid }" ng-show="domainConfigure.adding">
<label class="control-label">Domain name</label>
<input type="text" class="form-control" ng-model="domainConfigure.newDomain" name="newDomain" ng-disabled="domainConfigure.busy" placeholder="example.com" ng-required="domainConfigure.adding" autofocus>
</div>
<div class="form-group">
<label class="control-label">DNS API provider</label>
<select class="form-control" ng-model="domainConfigure.provider" ng-options="a.value as a.name for a in dnsProvider" ng-change="domainConfigure.setDefaultTlsProvider()"></select>
2018-01-22 13:01:38 -08:00
</div>
<!-- Route53 -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'route53'">
2018-06-04 21:06:44 -07:00
<label class="control-label">Access Key Id</label>
2018-01-22 13:01:38 -08:00
<input type="text" class="form-control" ng-model="domainConfigure.accessKeyId" name="accessKeyId" ng-disabled="domainConfigure.busy" ng-minlength="16" ng-maxlength="32" ng-required="domainConfigure.provider === 'route53'">
</div>
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'route53'">
2018-06-04 21:06:44 -07:00
<label class="control-label">Secret Access Key</label>
2018-01-22 13:01:38 -08:00
<input type="text" class="form-control" ng-model="domainConfigure.secretAccessKey" name="secretAccessKey" ng-disabled="domainConfigure.busy" ng-required="domainConfigure.provider === 'route53'">
</div>
<!-- Google Cloud DNS -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'gcdns'">
2018-06-04 21:06:44 -07:00
<label class="control-label">Service Account Key</label>
2018-01-22 13:01:38 -08:00
<div class="input-group">
<input type="file" id="gcdnsKeyFileInput" style="display:none"/>
<input type="text" class="form-control" placeholder="Service Account Key" ng-model="domainConfigure.gcdnsKey.keyFileName" id="gcdnsKeyInput" name="cert" onclick="getElementById('gcdnsKeyFileInput').click();" style="cursor: pointer;" ng-disabled="domainConfigure.busy" ng-required="domainConfigure.provider === 'gcdns'">
<span class="input-group-addon">
<i class="fa fa-upload" onclick="getElementById('gcdnsKeyFileInput').click();"></i>
</span>
</div>
</div>
<!-- DigitalOcean -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'digitalocean'">
2018-06-04 21:06:44 -07:00
<label class="control-label">DigitalOcean Token</label>
2018-01-22 13:01:38 -08:00
<input type="text" class="form-control" ng-model="domainConfigure.digitalOceanToken" name="digitalOceanToken" ng-disabled="domainConfigure.busy" ng-required="domainConfigure.provider === 'digitalocean'">
</div>
<!-- Gandi -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'gandi'">
<label class="control-label">Gandi API Key</label>
<input type="text" class="form-control" ng-model="domainConfigure.gandiApiKey" name="gandiApiKey" ng-disabled="domainConfigure.busy" ng-required="domainConfigure.provider === 'gandi'">
</div>
2018-05-06 21:52:25 -07:00
<!-- GoDaddy -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'godaddy'">
<label class="control-label">API Key <sup><a href="https://developer.godaddy.com/keys" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<input type="text" class="form-control" ng-model="domainConfigure.godaddyApiKey" name="apiKey" ng-disabled="domainConfigure.busy" ng-minlength="1" ng-required="domainConfigure.provider === 'godaddy'">
</div>
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'godaddy'">
<label class="control-label">API Secret</label>
<input type="text" class="form-control" ng-model="domainConfigure.godaddyApiSecret" name="apiSecret" ng-disabled="domainConfigure.busy" ng-required="domainConfigure.provider === 'godaddy'">
</div>
2018-01-22 13:01:38 -08:00
<!-- Cloudflare -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'cloudflare'">
2018-06-04 21:06:44 -07:00
<label class="control-label">Global API Key</label>
2018-01-23 18:15:48 -08:00
<input type="text" class="form-control" ng-model="domainConfigure.cloudflareToken" name="cloudflareToken" placeholder="Global API Key" ng-required="domainConfigure.provider === 'cloudflare'" ng-disabled="domainConfigure.busy">
2018-01-22 13:01:38 -08:00
</div>
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'cloudflare'">
2018-06-04 21:06:44 -07:00
<label class="control-label">Cloudflare Email</label>
2018-01-22 13:01:38 -08:00
<input type="email" class="form-control" ng-model="domainConfigure.cloudflareEmail" name="cloudflareEmail" placeholder="Cloudflare Account Email" ng-required="domainConfigure.provider === 'cloudflare'" ng-disabled="domainConfigure.busy">
</div>
2018-05-09 12:24:46 +02:00
<!-- Name.com -->
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'namecom'">
2018-06-04 21:06:44 -07:00
<label class="control-label">Name.com Username</label>
2018-05-09 12:24:46 +02:00
<input type="text" class="form-control" ng-model="domainConfigure.nameComUsername" name="nameComUsername" ng-disabled="domainConfigure.busy" ng-required="domainConfigure.provider === 'namecom'">
</div>
<div class="form-group" ng-class="{ 'has-error': false }" ng-show="domainConfigure.provider === 'namecom'">
2018-06-04 21:06:44 -07:00
<label class="control-label">API Token <sup><a href="https://www.name.com/account/settings/api" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
2018-05-09 12:24:46 +02:00
<input type="text" class="form-control" ng-model="domainConfigure.nameComToken" name="nameComToken" ng-disabled="domainConfigure.busy" ng-minlength="1" ng-required="domainConfigure.provider === 'namecom'">
</div>
2018-09-12 11:45:07 -07:00
<p class="small text-info" ng-show="domainConfigure.provider === 'wildcard'">
2018-01-22 13:01:38 -08:00
Setup <i>A</i> records for <b>*.{{ domainConfigure.newDomain || domainConfigure.domain.domain }}</b> and <b>{{ domainConfigure.newDomain || domainConfigure.domain.domain }}</b> to this server's IP.
</p>
2018-09-12 11:45:07 -07:00
<p class="small text-info" ng-show="domainConfigure.provider === 'manual'">
2018-03-12 15:04:37 -07:00
<b>All DNS records have to be setup manually before each app installation.</b>
2018-01-22 13:01:38 -08:00
</p>
<p class="small text-info" ng-show="needsPort80(domainConfigure.provider, domainConfigure.tlsConfig.provider)">Let's Encrypt requires your server to be reachable on port 80</p>
<a href="" ng-click="domainConfigure.advancedVisible = true" ng-hide="domainConfigure.advancedVisible">Advanced settings...</a>
<div uib-collapse="!domainConfigure.advancedVisible">
2018-01-22 13:01:38 -08:00
2018-10-30 20:52:03 -07:00
<div ng-show="false">
<label class="control-label">
2018-09-05 19:32:53 -07:00
<input type="checkbox" ng-model="domainConfigure.hyphenatedSubdomains" name="hyphenatedSubdomains" ng-disabled="domainConfigure.busy"/>&nbsp; Hyphenate Subdomains
2018-08-27 13:50:13 -07:00
</label>
2018-09-05 19:32:53 -07:00
<p>When enabled, apps are installed into <code>&lt;location&gt;-&lt;domain&gt;</code></p>
</div>
<div class="form-group">
2018-08-27 13:50:13 -07:00
<label class="control-label">Zone Name (Optional)</label>
<input type="text" class="form-control" ng-model="domainConfigure.zoneName" name="zoneName" ng-disabled="domainConfigure.busy">
</div>
<div class="form-group">
2018-05-15 15:46:24 -07:00
<label class="control-label">Certificate Provider</label>
<select class="form-control" ng-model="domainConfigure.tlsConfig.provider" ng-options="a.value as a.name for a in tlsProvider"></select>
</div>
2018-08-27 12:03:01 -07:00
<!-- Fallback certificate -->
<div ng-show="domainConfigure.tlsConfig.provider !== 'fallback'">
<label class="control-label">Fallback Certificate (optional)</label>
<p>
Certificates are automatically obtained and renewed from <a href="https://letsencrypt.org/" target="_blank">Lets Encrypt</a>. See the current rate limit <a href="https://letsencrypt.org/docs/rate-limits/" target="_blank">here</a>.
This wildcard certificate will be used should getting a Lets Encrypt certificate fail. If not provided, an automatically generated self-signed certificate will be used as fallback.
</p>
</div>
<div ng-show="domainConfigure.tlsConfig.provider === 'fallback'">
<label class="control-label">Custom Certificate</label>
<p>
This <a href="https://cloudron.io/documentation/certificates/#setting-custom-certificates" target="_blank">wildcard certificate</a> will be used for all apps on this domain. If not provided, a self-signed certificate will be automatically generated.
</p>
</div>
<div class="form-group" ng-class="{ 'has-error': (!fallbackCert.cert.$dirty && fallbackCert.error) }">
<div class="input-group">
<input type="file" id="fallbackCertFileInput" style="display:none"/>
<input type="text" class="form-control" placeholder="Certificate" ng-model="domainConfigure.fallbackCert.certificateFileName" name="cert" onclick="getElementById('fallbackCertFileInput').click();" style="cursor: pointer;" ng-disabled="domainConfigure.busy">
<span class="input-group-addon">
<i class="fa fa-upload" onclick="getElementById('fallbackCertFileInput').click();"></i>
</span>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error': (!fallbackCert.key.$dirty && fallbackCert.error) }">
<div class="input-group">
<input type="file" id="fallbackKeyFileInput" style="display:none"/>
<input type="text" class="form-control" placeholder="Key" ng-model="domainConfigure.fallbackCert.keyFileName" id="fallbackKeyInput" name="key" onclick="getElementById('fallbackKeyFileInput').click();" style="cursor: pointer;" ng-disabled="domainConfigure.busy">
<span class="input-group-addon">
<i class="fa fa-upload" onclick="getElementById('fallbackKeyFileInput').click();"></i>
</span>
</div>
</div>
2018-08-27 13:50:13 -07:00
</div> <!-- advanced -->
2018-01-22 13:01:38 -08:00
<input class="ng-hide" type="submit" ng-disabled="domainConfigureForm.$invalid || domainConfigure.busy"/>
</fieldset>
</form>
</div>
<div class="modal-footer ">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-outline btn-success pull-right" ng-click="domainConfigure.submit()" ng-disabled="domainConfigureForm.$invalid || domainConfigure.busy">
<i class="fa fa-circle-notch fa-spin" ng-show="domainConfigure.busy"></i> Save
2018-01-22 13:01:38 -08:00
</button>
</div>
</div>
</div>
</div>
<!-- Modal domain migrate -->
<div class="modal fade" id="domainMigrateModal" tabindex="-1" role="dialog">
2018-12-11 10:19:01 -08:00
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Migrate to {{ domainMigrate.domain.domain }} ?</h4>
</div>
<div class="modal-body">
<p>Moving to a custom domain will retain all your apps and data and will take around 15 minutes.</p>
<br/>
<fieldset>
<form role="form" name="domainMigrateForm" ng-submit="domainMigrate.submit()" autocomplete="off">
<div class="form-group" ng-class="{ 'has-error': (domainMigrateForm.password.$dirty && domainMigrateForm.password.$invalid) || (!domainMigrateForm.password.$dirty && domainMigrate.error) }">
<label class="control-label">Provide your password to confirm this action</label>
<div class="control-label" ng-show="(domainMigrateForm.password.$dirty && domainMigrateForm.password.$invalid) || (!domainMigrateForm.password.$dirty && domainMigrate.error)">
<small ng-show=" domainMigrateForm.password.$dirty && domainMigrateForm.password.$invalid">Password required</small>
<small ng-show="!domainMigrateForm.password.$dirty && domainMigrate.error">{{ domainMigrate.error }}</small>
2018-01-22 13:01:38 -08:00
</div>
2018-12-11 10:19:01 -08:00
<input type="password" class="form-control" ng-model="domainMigrate.password" id="domainMigratePasswordInput" name="password" required autofocus>
</div>
2018-01-22 13:01:38 -08:00
2018-12-11 10:19:01 -08:00
<input class="ng-hide" type="submit" ng-disabled="domainMigrateForm.$invalid || busy"/>
</form>
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" ng-click="domainMigrate.submit()" ng-disabled="domainMigrateForm.$invalid || domainMigrate.busy"><i class="fa fa-circle-notch fa-spin" ng-show="domainMigrate.busy"></i> Migrate</button>
2018-01-22 13:01:38 -08:00
</div>
</div>
</div>
2018-12-11 10:19:01 -08:00
</div>
2018-01-22 13:01:38 -08:00
<!-- Modal domain remove -->
<div class="modal fade" id="domainRemoveModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Really remove {{ domainRemove.domain.domain }} ?</h4>
</div>
<div class="modal-body">
<fieldset>
<form role="form" name="domainRemoveForm" ng-submit="domainRemove.submit()" autocomplete="off">
<div class="form-group" ng-class="{ 'has-error': (domainRemoveForm.password.$dirty && domainRemoveForm.password.$invalid) || (!domainRemoveForm.password.$dirty && domainRemove.error) }">
<label class="control-label">Provide your password to confirm this action</label>
<div class="control-label" ng-show="(domainRemoveForm.password.$dirty && domainRemoveForm.password.$invalid) || (!domainRemoveForm.password.$dirty && domainRemove.error)">
<small ng-show=" domainRemoveForm.password.$dirty && domainRemoveForm.password.$invalid">Password required</small>
<small ng-show="!domainRemoveForm.password.$dirty && domainRemove.error">{{ domainRemove.error }}</small>
</div>
<input type="password" class="form-control" ng-model="domainRemove.password" id="domainRemovePasswordInput" name="password" required autofocus>
</div>
<input class="ng-hide" type="submit" ng-disabled="domainRemoveForm.$invalid || busy"/>
</form>
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" ng-click="domainRemove.submit()" ng-disabled="domainRemoveForm.$invalid || domainRemove.busy"><i class="fa fa-circle-notch fa-spin" ng-show="domainRemove.busy"></i> Remove</button>
2018-01-22 13:01:38 -08:00
</div>
</div>
</div>
</div>
<div class="content">
<div class="text-left">
2018-01-25 11:17:15 -08:00
<h1>Domains <button class="btn btn-primary btn-outline pull-right" ng-click="domainConfigure.show()"><i class="fa fa-plus"></i> Add Domain</button></h1>
2018-01-22 13:01:38 -08:00
</div>
<div class="card card-large">
<div class="row ng-hide" ng-show="!ready">
<div class="col-lg-12 text-center">
<h2><i class="fa fa-circle-notch fa-spin"></i></h2>
2018-01-22 13:01:38 -08:00
</div>
</div>
<div class="row animateMeOpacity ng-hide" ng-show="ready">
<div class="col-lg-12">
<table class="table table-hover" style="margin-top: 10px;">
<thead>
<tr>
<th style="width: 10px"></th>
<th>Domain</th>
<th class="text-left hidden-xs hidden-sm">Provider</th>
<th style="width: 100px" class="text-right">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="domain in domains">
<td>
<i class="fa fa-lock" ng-show="domain.locked" uib-tooltip="This domain is locked and cannot be edited"></i>
</td>
<td class="elide-table-cell hand" ng-click="domain.provider !== 'caas' && !domain.locked && domainConfigure.show(domain)">
{{ domain.domain }}
</td>
<td class="text-left elide-table-cell hidden-xs hidden-sm hand" ng-click="domain.provider !== 'caas' && !domain.locked && domainConfigure.show(domain)">
{{ prettyProviderName(domain) }}
</td>
<td class="text-right no-wrap" style="vertical-align: bottom">
<button class="btn btn-xs btn-default" ng-click="domainMigrate.show(domain)" ng-show="domain.domain !== config.adminDomain && domain.provider !== 'caas' && provider === 'caas'" title="Migrate Domain"><i class="fa fa-exchange"></i></button>
<button class="btn btn-xs btn-default" ng-click="domainConfigure.show(domain)" ng-show="domain.provider !== 'caas' && !domain.locked" title="Edit Domain"><i class="fa fa-pencil-alt"></i></button>
<button class="btn btn-xs btn-danger" ng-click="domainRemove.show(domain)" ng-show="domain.provider !== 'caas' && !domain.locked" title="Remove Domain"><i class="far fa-trash-alt"></i></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
2018-12-11 09:57:46 -08:00
</div>
<div class="text-left" ng-show="!config.managed">
<h3>Renew certificates</h3>
</div>
<div class="card">
<div class="row">
<div class="col-md-12">
<p>
2018-12-13 13:58:08 +01:00
Cloudron renews Let's Encrypt certificates automatically. Use this option to trigger a renewal immediately.
2018-12-11 09:57:46 -08:00
</p>
2018-01-22 13:01:38 -08:00
</div>
</div>
<div class="row">
<div class="col-md-12" style="margin-bottom: 10px;">
<div ng-show="renewCerts.busy" class="progress progress-striped active animateMe">
<div class="progress-bar progress-bar-success" role="progressbar" style="width: {{ renewCerts.percent }}%"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<p ng-show="renewCerts.busy">{{ renewCerts.message }}</p>
<p ng-hide="renewCerts.busy">
<div class="has-error" ng-show="!renewCerts.active">{{ renewCerts.errorMessage }}</div>
</p>
</div>
<div class="col-md-6 text-right">
<button class="btn btn-outline btn-primary" ng-click="renewCerts.renew()" ng-disabled="renewCerts.busy" style="margin-right: 10px">Renew All Certs</button>
<a class="btn btn-primary pull-right" ng-href="/logs.html?taskId={{renewCerts.taskId}}" ng-enabled="renewCerts.taskId" target="_blank">Show Logs</a>
</div>
</div>
2018-01-22 13:01:38 -08:00
</div>
<div class="text-left" ng-show="!config.managed">
<h3>Dynamic DNS</h3>
</div>
<div class="card" ng-show="!config.managed">
<div class="row">
<div class="col-md-12">
<p>
Enable this option to keep all your DNS records in sync with a changing IP address.
This is useful when Cloudron runs in a network with a frequently changing public IP address like a home connection.
</p>
<p class="text-danger" ng-show="dyndnsConfigure.error"><br/>{{ dyndnsConfigure.error }}</p>
2018-11-09 11:24:19 -08:00
<div class="checkbox">
<label>
<input type="checkbox" ng-model="dyndnsConfigure.enabled" name="dynamicDns" ng-disabled="dyndnsConfigure.busy"/>&nbsp; Use Dynamic DNS
</label>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<span class="text-success text-bold" ng-show="dyndnsConfigure.success">Saved</span>
</div>
<div class="col-md-6 text-right">
<button class="btn btn-outline btn-primary pull-right" ng-click="dyndnsConfigure.submit()" ng-disabled="dyndnsConfigure.currentState === dyndnsConfigure.enabled"><i class="fa fa-circle-notch fa-spin" ng-show="dyndnsConfigure.busy"></i> Save</button>
</div>
</div>
</div>
2018-01-22 13:01:38 -08:00
</div>