It looks on some VPS, the grub then asks the user to re-install
since the disk name has changed/moved (presumably because the
image was created on a server with a different disk name)
This allows one to easily add "dev.staging@domain.com" etc without having to create
yet another domain. This plays well with the concept that we have a
mail domain for every domain. So we get mails from @domain.com working for
these subdomain installations.
The command fails in a subshell and strange things happen
==> installer: update cloudron-syslog
/tmp/box-src-hotfix/scripts/installer.sh: line 99: /usr/local/cloudron-syslog/bin/cloudron-syslog: No such file or directory
/tmp/box-src-hotfix/scripts/installer.sh: line 99: : command not found
This allows us to enable email server but not setup the dns records
yet. Useful for importing existing mailboxes from another server
without adjusting the DNS.
The following packages have unmet dependencies:
docker-ce : Depends: libseccomp2 (>= 2.3.0) but 2.2.3-3ubuntu3 is to be installed
E: Unable to correct problems, you have held broken packages.
we have to track the members of a list in the mail app separately
from groups. this is required because users can now have multiple
mailboxes. and because of that we cannot do a 1-1 mapping of group
members to mailboxes anymore. the ui is changed to select mailboxes
when creating a list.
chunk uploads get a timeout of 2mins (derived from http.timeout).
On servers like kimsufi, uploads takes forever (100 MB/sec limit).
Currently, our upload code does not dynamically adapt itself to
changing the concurrency when network is slow.
DO API takes very long to respond at times :/ Currently, there is
no easy way to reset the timeout middleware timeout. We should add
this feature upstream (https://github.com/expressjs/timeout/issues/26)
DNS records can now be a A record or a CNAME record. All we care
about is them resolving to the public IP of the server somehow.
The main reason for this change is that altDomain is migrated into
domains table and the DNS propagation checks have to work after that.
(previously, the 'altDomain' was a signal for a CNAME check which now
cannot be done post-migration).
In the future, we can make this more sophisticated to instead maybe
do a well-known URI query. That way it will work even if there is
some proxy like Cloudflare in the middle.
Fixes#503
In the e2e, we did not check the webadminStatus after a dnsSetup
and immediately rushed into restore. This ended up mangling the
cert/key files of the admin domain.
We used to always use nginx cert dir. When custom fallback certs
were set, we used to copy it in boxdata cert dir and then nginx cert dir.
The issue is then that we have to copy all certs to nginx cert dir on
cloudron restore.
To fix this, we simply give priority to nginx cert dir and not copy
around certs anymore. caas cert will reside in nginx cert dir and
not get backed up, as expected.
when certs change, we have to call into nginx anyway. since they
go hand in hand, just merge those files. modern reverse proxies
do this job integrated already.
This is required since some older cloudrons have a mixed bag of
collations and thus charsets and we add foreign keys across those, which
require the same collation
During domain migration, the box code restarts. the getStatus() will
fail temporarily. In the future, we can make this code forward to
error.html after a few retries.
All these are already fetched the first time in main.js
* Fetch apps periodically only in the apps view. This is mostly for the
installationState. We can optimize this a bit more later depending on
if any app is in non-running state.
* profile hardly changes, no need to fetch this over and over
* config hardly changes, but is fetched primarily for the update flag
It seems there is a race where the delete gets triggered even before the
file upload is complete. as a result, the delete succeeds but the file
is left on gcs.
npm WARN The package gulp-sass is included as both a dev and production dependency.
npm WARN The package hock is included as both a dev and production dependency.
npm WARN The package request is included as both a dev and production dependency.
The following migrations are already released in 1.8.3:
20171116203507-apps-rename-newConfigJson-to-updateConfigJson.js
20171116224051-apps-rename-lastBackupId-to-restoreConfigJson.js
For new cloudrons this will first remove the previously added group and
mailbox entry from the db migration scripts and readds it once we have a
domain on owner creation
This adds domains table and adjusts the apps and mailboxes table accordingly
Also ensure we explicitly set the table collation, this is required
for the foreign key from apps table (utf8) and the newly created
domains table, which by default now would be utf8mb4
Put db table constraint for mailboxes.domain
Update the schema file
https://docs.docker.com/engine/api/v1.32/#tag/Network
"Note that it uses a different, smaller representation of a network
than inspecting a single network. For example, the list of containers
attached to the network is not propagated in API versions 1.28 and up."
Verified using:
curl --unix-socket /var/run/docker.sock http::/networks/cloudron
LE contacts the server by hostname and not by IP. This means that
when installing and reconfiguring the app it hits the default_server
route since nginx configs for the app are not generated at.
When doing in the daily cert renew, the nginx configs exist and we
are unable to renew the certs.
MySQL restarts randomly fail on our CI systems. This is easily
reproducible:
root@smartserver:~# cp /tmp/mysql.cnf . && systemctl restart mysql && echo "Yes"
Yes
root@smartserver:~# cp /tmp/mysql.cnf . && systemctl restart mysql && echo "Yes"
Yes
root@smartserver:~# cp /tmp/mysql.cnf . && systemctl restart mysql && echo "Yes"
Job for mysql.service failed. See "systemctl status mysql.service" and "journalctl -xe" for details.
There also seems some apparmor issue:
[ 7389.111704] audit: type=1400 audit(1509404778.110:829): apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/sys/devices/system/node/" pid=15618 comm="mysqld" requested_mask="r" denied_mask="r" fsuid=112 ouid=0
The apparmor issue is reported in https://bugs.launchpad.net/ubuntu/+source/mysql-5.7/+bug/1610765,
https://bugs.launchpad.net/ubuntu/+source/mysql-5.7/+bug/1658233 and
https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1658239
The e2e is failing sporadically with:
==> Changing ownership
==> Adding automated configs
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
Maybe the dhparam creation is doing something causing mysql to not respond.
App backup can take a long time or possibly not work at all. For such
cases, do not stop the app or leave it in some errored state.
newConfigJson is the new config to be updated to. This ensures that
the db has correct app info during the update.
SOS does not like multipart uploads. They just fail randomly.
As a fix, we try to detect filesystem files and skip multipart uploads
for files < 5GB. For > 5GB, we do multipart upload anyways (mostly fails).
The box backup is switched to flat-file for exoscale for the reason
above.
this is a bit of a hack and we should add another way to set the progress
(maybe via backups.setProgress or via a progress callback). this is because
some methods like removeDir can be called from backuptask and from box code.
This is required for various small reasons:
* dir iteration with a way to pass messagein back to the upload() easily
* can be killed independently of box code
* allows us to run sync (blocking) commands in the upload logic
On some provider (https://www.nine.ch) disabling IPv6 makes unbound
not respond to the DNS queries.
Also, I was unable to test with prefer-ip6 to 'no' because unbound fails:
unbound[5657]: /etc/unbound/unbound.conf.d/cloudron-network.conf:8: error: unknown keyword 'no'
unbound[5657]: read /etc/unbound/unbound.conf failed: 3 errors in configuration file
* Install in subdomain 'test'
* Move to subdomain 'test2'
* Move to another existing subdomain 'www' (this should be detected as conflict)
* Move to subdomain 'www2' (this should not remove 'www'). This is why dnsRecordId exists.
We already store JSON blobs there and the gce dns backend
will require a larger blob for a certificate.
Since we use innodb the storage format in TEXT will only be different
if the data is large
The initial plan was to make app volumes to be set using a database
field but this makes the app backups non-portable. It also complicates
things wrt to app and server restores.
For now, ignore the problem and let them be symlinked.
Fixes#394
Fixes selection while clicking on empty flexbox space.
This only happens in firefox and seems to be a bug in firefox
flexbox implementation, where the first child element with a
non zero size, in a flexbox managed `block` element, has the
`float` property.
Fixes#405
Since the cloudflare email input field is above the password field
some browsers will automatically autofill it with the username
as it looks like a login form. So we add a hidden unused input field
which gets autofilled instead :-/
This skips the app from a backup when doing a full box backup and
simply reuses the previous backup.
The app can still be explicitly backed up using 'cloudron backup'
and explicitly restored using 'cloudron restore --backup'.
When restoring the box, it all depends on the app's last backup.
Fixes#311
on some VPS like scaleway this is not installed.
This is why docker with devicemapper was using ext4 and not devmapper
devmapper: XFS is not supported in your system. Either the kernel doesn't support it or mkfs.xfs is not in your PATH. Defaulting to ext4 filesystem"
npm WARN deprecated ejs-cli@1.2.0: This has breaking change. (in ejs package) use <= 2.0.0.
npm WARN deprecated node-uuid@1.4.8: Use uuid module instead
npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated minimatch@0.2.14: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated graceful-fs@1.2.3: graceful-fs v3.0.0 and before will fail on node releases >= v7.0. Please update to graceful-fs@^4.0.0 as soon as possible. Use 'npm ls graceful-fs' to find it in the tree.
logrotate config files may contain arbitrary commands which are
exectued as root, thus the config files have to be owned by root.
This is the reason we need the sudo scripts :-/
To test the generated scripts, just run:
$ logrotate /etc/logrotate.conf -v
Fixes#396
The built-in df plugin cannot do the following:
* if we choose by type ext4, we want to skip devicemapper (on scaleway)
* the MountPoint of the appsdata directory is not possible to know at install time
Fixes#398
The original intention was to collect information on the data
dirs as well but we have long moved away from that design.
On some VPS like scaleway, this ends up collecting info on
devicemapper stuff (which are on ext4, not sure why).
In future, we should collect info of other disks as well (#348)
Fixes#389
Note that this is not a flag on the mailboxes because we might theoretically
support forwarding to some other external domain in the future.
Part of #33
By default, this addon provides a single database on MySQL 5.6.19. The database is already created and the application
only needs to create the tables.
Exported environment variables:
```
MYSQL_URL= # the mysql url (only set when using a single database, see below)
MYSQL_USERNAME= # username
MYSQL_PASSWORD= # password
MYSQL_HOST= # server IP/hostname
MYSQL_PORT= # server port
MYSQL_DATABASE= # database name (only set when using a single database, see below)
```
For debugging, [cloudron exec](https://www.npmjs.com/package/cloudron) can be used to run the `mysql` client within the context of the app:
```
cloudron exec
> mysql --user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} --host=${MYSQL_HOST} ${MYSQL_DATABASE}
```
The `multipleDatabases` option can be set to `true` if the app requires more than one database. When enabled,
the following environment variables are injected:
```
MYSQL_DATABASE_PREFIX= # prefix to use to create databases
```
## oauth
The Cloudron OAuth 2.0 provider can be used in an app to implement Single Sign-On.
Exported environment variables:
```
OAUTH_CLIENT_ID= # client id
OAUTH_CLIENT_SECRET= # client secret
```
The callback url required for the OAuth transaction can be contructed from the environment variables below:
```
APP_DOMAIN= # hostname of the app
APP_ORIGIN= # origin of the app of the form https://domain
API_ORIGIN= # origin of the OAuth provider of the form https://my-cloudrondomain
```
OAuth2 URLs can be constructed as follows:
```
AuthorizationURL = ${API_ORIGIN}/api/v1/oauth/dialog/authorize # see above for API_ORIGIN
TokenURL = ${API_ORIGIN}/api/v1/oauth/token
```
The token obtained via OAuth has a restricted scope wherein they can only access the [profile API](/references/api.html#profile). This restriction
is so that apps cannot make undesired changes to the user's Cloudron.
We currently provide OAuth2 integration for Ruby [omniauth](https://git.cloudron.io/cloudron/omniauth-cloudron) and Node.js [passport](https://git.cloudron.io/cloudron/passport-cloudron).
## postgresql
By default, this addon provides PostgreSQL 9.4.4.
Exported environment variables:
```
POSTGRESQL_URL= # the postgresql url
POSTGRESQL_USERNAME= # username
POSTGRESQL_PASSWORD= # password
POSTGRESQL_HOST= # server name
POSTGRESQL_PORT= # server port
POSTGRESQL_DATABASE= # database name
```
The postgresql addon whitelists the hstore and pg_trgm extensions to be installable by the database owner.
For debugging, [cloudron exec](https://www.npmjs.com/package/cloudron) can be used to run the `psql` client within the context of the app:
The `memoryLimit` field is the maximum amount of memory (including swap) in bytes an app is allowed to consume before it
gets killed and restarted.
By default, all apps have a memoryLimit of 256MB. For example, to have a limit of 500MB,
```
"memoryLimit": 524288000
```
## maxBoxVersion
Type: semver string
Required: no
The `maxBoxVersion` field is the maximum box version that the app can possibly run on. Attempting to install the app on
a box greater than `maxBoxVersion` will fail.
This is useful when a new box release introduces features which are incompatible with the app. This situation is quite
unlikely and it is recommended to leave this unset.
## minBoxVersion
Type: semver string
Required: no
The `minBoxVersion` field is the minimum box version that the app can possibly run on. Attempting to install the app on
a box lesser than `minBoxVersion` will fail.
This is useful when the app relies on features that are only available from a certain version of the box. If unset, the
default value is `0.0.1`.
## postInstallMessage
Type: markdown string
Required: no
The `postInstallMessageField` is a message that is displayed to the user after an app is installed.
The intended use of this field is to display some post installation steps that the user has to carry out to
complete the installation. For example, displaying the default admin credentials and informing the user to
to change it.
The message can have the following special tags:
*`<sso> ... </sso>` - Content in `sso` blocks are shown if SSO enabled.
*`<nosso> ... </nosso>`- Content in `nosso` blocks are shows when SSO is disabled.
## optionalSso
Type: boolean
Required: no
The `optionalSso` field can be set to true for apps that can be installed optionally without using the Cloudron user management.
This only applies if any Cloudron auth related addons are used. When set, the Cloudron will not inject the auth related addon environment variables.
Any app startup scripts have to be able to deal with missing env variables in this case.
## tagline
Type: one-line string
Required: no (required for submitting to the Cloudron Store)
The `tagline` is used by the Cloudron Store to display a single line short description of the application.
```
"tagline": "The very best note keeper"
```
## tags
Type: Array of strings
Required: no (required for submitting to the Cloudron Store)
The `tags` are used by the Cloudron Store for filtering searches by keyword.
```
"tags": [ "git", "version control", "scm" ]
```
## targetBoxVersion
Type: semver string
Required: no
The `targetBoxVersion` field is the box version that the app was tested on. By definition, this version has to be greater
than the `minBoxVersion`.
The box uses this value to enable compatibility behavior of APIs. For example, an app sets the targetBoxVersion to 0.0.5
and is published on the store. Later, box version 0.0.10 introduces a new feature that conflicts with how apps used
to run in 0.0.5 (say SELinux was enabled for apps). When the box runs such an app, it ensures compatible behavior
and will disable the SELinux feature for the app.
If unspecified, this value defaults to `minBoxVersion`.
## tcpPorts
Type: object
Required: no
Syntax: Each key is the environment variable. Each value is an object containing `title`, `description` and `defaultValue`.
An optional `containerPort` may be specified.
The `tcpPorts` field provides information on the non-http TCP ports/services that your application is listening on. During
installation, the user can decide how these ports are exposed from their Cloudron.
For example, if the application runs an SSH server at port 29418, this information is listed here. At installation time,
the user can decide any of the following:
* Expose the port with the suggested `defaultValue` to the outside world. This will only work if no other app is being exposed at same port.
* Provide an alternate value on which the port is to be exposed to outside world.
* Disable the port/service.
To illustrate, the application lists the ports as below:
```
"tcpPorts": {
"SSH_PORT": {
"title": "SSH Port",
"description": "SSH Port over which repos can be pushed & pulled",
"defaultValue": 29418,
"containerPort": 22
}
},
```
In the above example:
*`SSH_PORT` is an app specific environment variable. Only strings, numbers and _ (underscore) are allowed. The author has to ensure that they don't clash with platform profided variable names.
*`title` is a short one line information about this port/service.
*`description` is a multi line description about this port/service.
*`defaultValue` is the recommended port value to be shown in the app installation UI.
*`containerPort` is the port that the app is listening on (recall that each app has it's own networking namespace).
In more detail:
* If the user decides to disable the SSH service, this environment variable `SSH_PORT` is absent. Applications _must_ detect this on
start up and disable these services.
*`SSH_PORT` is set to the value of the exposed port. Should the user choose to expose the SSH server on port 6000, then the
value of SSH_PORT is 6000.
*`defaultValue` is **only** used for display purposes in the app installation UI. This value is independent of the value
that the app is listening on. For example, the app can run an SSH server at port 22 but still recommend a value of 29418 to the user.
*`containerPort` is the port that the app is listening on. The Cloudron runtime will _bridge_ the user chosen external port
with the app specific `containerPort`. Cloudron Apps are containerized and each app has it's own networking namespace.
As a result, different apps can have the same `containerPort` value because these values are namespaced.
* The environment variable `SSH_PORT` may be used by the app to display external URLs. For example, the app might want to display
the SSH URL. In such a case, it would be incorrect to use the `containerPort` 22 or the `defaultValue` 29418 since this is not
the value chosen by the user.
*`containerPort` is optional and can be omitted, in which case the bridged port numbers are the same internally and externally.
Some apps use the same variable (in their code) for listen port and user visible display strings. When packaging these apps,
it might be simpler to listen on `SSH_PORT` internally. In such cases, the app can omit the `containerPort` value and should
instead reconfigure itself to listen internally on `SSH_PORT` on each start up.
## title
Type: string
Required: yes
The `title` is the primary application title displayed on the Cloudron Store.
Example:
```
"title": "Gitlab"
```
## version
Type: semver string
Required: yes
The `version` field specifies a [semver](http://semver.org/) string. The version is used by the Cloudron to compare versions and to
determine if an update is available.
Example:
```
"version": "1.1.0"
```
## website
Type: url
Required: yes
The `website` field is a URL where the user can read more about the application.
`nginx` is often used as a reverse proxy in front of the application, to dispatch to different backend programs based on the request route or other characteristics. In such a case it is recommended to run nginx and the application through a process manager like `supervisor`.
The nginx configuration, provided with the base image, can be used by adding an application specific config file under `/etc/nginx/sites-enabled/` when building the docker image.
Since the base image nginx configuration is unpatched from the ubuntu package, the application configuration has to ensure nginx is using `/run/` instead of `/var/lib/nginx/` to support the read-only filesystem nature of a Cloudron application.
First create a new bucket for the backups, using the minio commandline tools or the webinterface. The bucket has to have **read and write** permissions.
The information to be copied to the Cloudron's backup settings form may look similar to:
The `Encryption key` is an arbitrary passphrase used to encrypt the backups. Keep the passphrase safe; it is
required to decrypt the backups when restoring the Cloudron.
# Email
Cloudron has a built-in email server. By default, it only sends out email on behalf of apps
(for example, password reset or notification). You can enable the email server for sending
and receiving mail on the `settings` page. This feature is only available if you have setup
a DNS provider like Digital Ocean or Route53.
Your server's IP plays a big role in how emails from our Cloudron get handled. Spammers
frequently abuse public IP addresses and as a result your Cloudron might possibly start
out with a bad reputation. The good news is that most IP based blacklisting services cool
down over time. The Cloudron sets up DNS entries for SPF, DKIM, DMARC automatically and
reputation should be easy to get back.
## Checklist
* If you are unable to receive mail, first thing to check is if your VPS provider lets you
receive mail on port 25.
* Digital Ocean - New accounts frequently have port 25 blocked. Write to their support to
unblock your server.
* EC2, Lightsail & Scaleway - Edit your security group to allow email.
* Setup a Reverse DNS PTR record to be setup for the `my` subdomain.
**Note:** PTR records are a feature of your VPS provider and not your domain provider.
* You can verify the PTR record [https://mxtoolbox.com/ReverseLookup.aspx](here).
* AWS EC2 & Lightsail - Fill the [PTR request form](https://aws-portal.amazon.com/gp/aws/html-forms-controller/contactus/ec2-email-limit-rdns-request).
* Digital Ocean - Digital Ocean sets up a PTR record based on the droplet's name. So, simply rename
your droplet to `my.<domain>`. Note that some new Digital Ocean accounts have [port 25 blocked](https://www.digitalocean.com/community/questions/port-25-smtp-external-access).
* Linode - Follow this [guide](https://www.linode.com/docs/networking/dns/setting-reverse-dns).
* Scaleway - Edit your security group to allow email and [reboot the server](https://community.online.net/t/security-group-not-working/2096) for the change to take effect. You can also set a PTR record on the interface with your `my.<domain>`.
* Check if your IP is listed in any DNSBL list [here](http://multirbl.valli.org/) and [here](http://www.blk.mx).
In most cases, you can apply for removal of your IP by filling out a form at the DNSBL manager site.
* When using wildcard or manual DNS backends, you have to setup the DMARC, MX records manually.
* Finally, check your spam score at [mail-tester.com](https://www.mail-tester.com/). The Cloudron
should get 100%, if not please let us know.
# CLI Tool
The [Cloudron tool](https://git.cloudron.io/cloudron/cloudron-cli) is useful for managing
a Cloudron. <b class="text-danger">The Cloudron CLI tool has to be installed & run on a Laptop or PC</b>
Once installed, you can install, configure, list, backup and restore apps from the command line.
## Linux & OS X
Installing the CLI tool requires node.js and npm. The CLI tool can be installed using the following command:
```
npm install -g cloudron
```
Depending on your setup, you may need to run this as root.
On OS X, it is known to work with the `openssl` package from homebrew.
See [#14](https://git.cloudron.io/cloudron/cloudron-cli/issues/14) for more information.
## Windows
The CLI tool does not work on Windows. Please contact us on our [chat](https://chat.cloudron.io) if you want to help with Windows support.
# Updates
Apps installed from the Cloudron Store are automatically updated every night.
The Cloudron platform itself updates in two ways: update or upgrade.
### Update
An **update** is applied onto the running server instance. Such updates are performed
every night. You can also use the Cloudron UI to initiate an update immediately.
The Cloudron will always make a complete backup before attempting an update. In the unlikely
case an update fails, it can be [restored](/references/selfhosting.html#restore).
### Upgrade
An **upgrade** requires a new OS image. This process involves creating a new server from scratch
with the latest code and restoring it from the last backup.
To upgrade follow these steps closely:
* Create a new backup - `cloudron machine backup create`
* List the latest backup - `cloudron machine backup list`
* Make the backup available for the new cloudron instance:
*`S3` - When storing backup ins S3, make the latest box backup public - files starting with `box_` (from v0.94.0) or `backup_`. This can be done from the AWS S3 console as seen here:
*`File system` - When storing backups in `/var/backups`, you have to make the box and the app backups available to the new Cloudron instance's `/var/backups`. This can be achieved in a variety of ways depending on the situation: like scp'ing the backup files to the machine before installation, mounting the external backup hard drive into the new Cloudron's `/var/backup` OR downloading a copy of the backup using `cloudron machine backup download` and uploading them to the new machine. After doing so, pass `file:///var/backups/<path to box backup>` as the `--restore-url` below.
* Create a new Cloudron by following the [installing](/references/selfhosting.html#installing) section.
When running the setup script, pass in the `--encryption-key` and `--restore-url` flags.
The `--encryption-key` is the backup encryption key. It can be displayed with `cloudron machine info`
Similar to the initial installation, a Cloudron upgrade looks like:
Note: When upgrading an old version of Cloudron (<= 0.94.0), pass the `--version 0.94.1` flag and then continue updating
from that.
* Finally, once you see the newest version being displayed in your Cloudron webinterface, you can safely delete the old server instance.
# Restore
To restore a Cloudron from a specific backup:
* Select the backup - `cloudron machine backup list`
* Make the backup public
*`S3` - Make the box backup publicly readable - files starting with `box_` (from v0.94.0) or `backup_`. This can be done from the AWS S3 console. Once the box has restored, you can make it private again.
*`File system` - When storing backups in `/var/backups`, you have to make the box and the app backups available to the new Cloudron instance's `/var/backups`. This can be achieved in a variety of ways depending on the situation: like scp'ing the backup files to the new machine before Cloudron installation OR mounting an external backup hard drive into the new Cloudron's `/var/backup` OR downloading a copy of the backup using `cloudron machine backup download` and uploading them to the new machine. After doing so, pass `file:///var/backups/<path to box backup>` as the `--restore-url` below.
* Create a new Cloudron by following the [installing](/references/selfhosting.html#installing) section.
When running the setup script, pass in the `version`, `encryption-key`, `domain` and `restore-url` flags.
The `version` field is the version of the Cloudron that the backup corresponds to (it is embedded
in the backup file name).
* Make the box backup private, once the upgrade is complete.
# Security
Security is a core feature of the Cloudron and we continue to push out updates to tighten the Cloudron's security policy. Our goal is that Cloudron users should be able to rely on Cloudron being secure out of the box without having to do manual configuration.
This section lists various security measures in place to protect the Cloudron.
## HTTP Security
* Cloudron admin has a CSP policy that prevents XSS attacks.
* Cloudron set various security related HTTP headers like `X-XSS-Protection`, `X-Download-Options`,
`X-Content-Type-Options`, `X-Permitted-Cross-Domain-Policies`, `X-Frame-Options` across all apps.
## SSL
* Cloudron enforces HTTPS across all apps. HTTP requests are automatically redirected to
HTTPS.
* The Cloudron automatically installs and renews certificates for your apps as needed. Should
installation of certificate fail for reasons beyond it's control, Cloudron admins will get a notification about it.
* Cloudron sets the `Strict-Transport-Security` header (HSTS) to protect apps against downgrade attacks
and cookie hijacking.
* Cloudron has A+ rating for SSL from [SSL Labs](https://cloudron.io/blog/2017-02-22-release-0.102.0.html).
## App isolation
* Apps are isolated completely from one another. One app cannot tamper with another apps' database or
local files. We achieve this using Linux Containers.
* Apps run with a read-only rootfs preventing attacks where the application code can be tampered with.
* Apps can only connect to addons like databases, LDAP, email relay using authentication.
* Apps are run with an AppArmor profile that disables many system calls and restricts access to `proc`
and `sys` filesystems.
* Most apps are run as non-root user. In the future, we intend to implement user namespaces.
* Each app is run in it's own subdomain as opposed to sub-paths. This ensures that XSS vulnerabilities
in one app doesn't [compromise](https://security.stackexchange.com/questions/24155/preventing-insecure-webapp-on-subdomain-compromise-security-of-main-webapp) other apps.
## Email
* Cloudron checks against the [Zen Spamhaus DNSBL](https://www.spamhaus.org/zen/) before accepting mail.
* Email can only be accessed with IMAP over TLS (IMAPS).
* Email can only be relayed (including same-domain emails) by authenticated users using SMTP/STARTTLS.
* Cloudron ensures that `MAIL FROM` is the same as the authenticated user. Users cannot spoof each other.
* All outbound mails from Cloudron are `DKIM` signed.
* Cloudron automatically sets up SPF, DMARC policies in the DNS for best email delivery.
*`journalctl -a -u box` to get debug output of box related code.
*`docker ps` will give you the list of containers. The addon containers are named as `mail`, `postgresql`,
`mysql` etc. If you want to get a specific container's log output, `journalctl -a CONTAINER_ID=<container_id>`.
# Alerts
The Cloudron will notify the Cloudron administrator via email if apps go down, run out of memory, have updates
available etc.
You will have to setup a 3rd party service like [Cloud Watch](https://aws.amazon.com/cloudwatch/) or [UptimeRobot](http://uptimerobot.com/) to monitor the Cloudron itself. You can use `https://my.<domain>/api/v1/cloudron/status`
as the health check URL.
# Help
If you run into any problems, join us at our [chat](https://chat.cloudron.io) or [email us](mailto:support@cloudron.io).
* Server Name - Use the `my` subdomain of your Cloudron
* Port - 993
* Connection Security - TLS
* Username/password - Same as your Cloudron credentials
## Sending email using SMTP
Use the following settings to send email.
* Server Name - Use the `my` subdomain of your Cloudron
* Port - 587
* Connection Security - STARTTLS
* Username/password - Same as your Cloudron credentials
## Email filters using Sieve
Use the following settings to setup email filtering users via Manage Sieve.
* Server Name - Use the `my` subdomain of your Cloudron
* Port - 4190
* Connection Security - TLS
* Username/password - Same as your Cloudron credentials
The [Rainloop](https://cloudron.io/appstore.html?app=net.rainloop.cloudronapp) and [Roundcube](https://cloudron.io/appstore.html?app=net.roundcube.cloudronapp)
apps are already pre-configured to use the above settings.
## Aliases
You can configure one or more aliases alongside the primary email address of each user. You can set aliases by editing the
user's settings, available behind the edit button in the user listing. Note that aliases cannot conflict with existing user names.
Pushing tag for rev [53b51eabcb89] on {https://cdn-registry-1.docker.io/v1/repositories/cloudron/img-2074d69134a7e0da3d6cdf3c53e241c4/tags/76cebfdd-7822-4f3d-af17-b3eb393ae604}
Build succeeded
```
## Installing
Now that we have built the image, we can install our latest build on the Cloudron
using the following command:
```
$ cloudron install
Using cloudron craft.selfhost.io
Using build 76cebfdd-7822-4f3d-af17-b3eb393ae604 from 1 hour ago
Location: tutorial # This is the location into which the application installs
App is being installed with id: 4dedd3bb-4bae-41ef-9f32-7f938995f85e
=> Waiting to start installation
=> Registering subdomain .
=> Verifying manifest .
=> Downloading image ..............
=> Creating volume .
=> Creating container
=> Setting up collectd profile ................
=> Waiting for DNS propagation ...
App is installed.
```
This makes the app available at https://tutorial-craft.selfhost.io.
Open the app in your default browser:
```
cloudron open
```
You should see `Hello World`.
# Testing
The application testing cycle involves `cloudron build` and `cloudron install`.
Note that `cloudron install` updates an existing app in place.
You can view the logs using `cloudron logs`. When the app is running you can follow the logs
using `cloudron logs -f`.
For example, you can see the console.log output in our server.js with the command below:
```
$ cloudron logs
Using cloudron craft.selfhost.io
2015-05-08T03:28:40.233940616Z Server running at port 8000
```
It is also possible to run a *shell* and *execute* arbitrary commands in the context of the application
process by using `cloudron exec`. By default, exec simply drops you into an interactive bash shell with
which you can inspect the file system and the environment.
```
$ cloudron exec
```
You can also execute arbitrary commands:
```
$ cloudron exec env # display the env variables that your app is running with
```
# Storing data
For file system storage, an app can use the `localstorage` addon to store data under `/app/data`.
When the `localstorage` addon is active, any data under /app/data is automatically backed up. When an
app is updated, /app/data already contains the data generated by the previous version.
*Note*: For convenience, the initial CloudronManifest.json generated by `cloudron init` already contains this
addon.
Let us put this theory into action by saving a *visit counter* as a file.
*server.js* has been modified to count the number of visitors on the site by storing a counter
in a file named ```counter.dat```.
File ```tutorial/server.js```
```javascript
var http = require('http'),
fs = require('fs'),
util = require('util');
var COUNTER_FILE = '/app/data/counter.dat';
var server = http.createServer(function (request, response) {
Now that we have built the image, we can install our latest build on the Cloudron
using the following command:
```
$ cloudron install
Using cloudron craft.selfhost.io
Using build 76cebfdd-7822-4f3d-af17-b3eb393ae604 from 1 hour ago
Location: tutorial # This is the location into which the application installs
App is being installed with id: 4dedd3bb-4bae-41ef-9f32-7f938995f85e
=> Waiting to start installation
=> Registering subdomain .
=> Verifying manifest .
=> Downloading image ..............
=> Creating volume .
=> Creating container
=> Setting up collectd profile ................
=> Waiting for DNS propagation ...
App is installed.
```
Open the app in your default browser:
```
cloudron open
```
You should see `Hello World`.
# Testing
The application testing cycle involves `cloudron build` and `cloudron install`.
Note that `cloudron install` updates an existing app in place.
You can view the logs using `cloudron logs`. When the app is running you can follow the logs
using `cloudron logs -f`.
For example, you can see the console.log output in our server.js with the command below:
```
$ cloudron logs
Using cloudron craft.selfhost.io
16:44:11 [main] Server running at port 8000
```
It is also possible to run a *shell* and *execute* arbitrary commands in the context of the application
process by using `cloudron exec`. By default, exec simply drops you into an interactive bash shell with
which you can inspect the file system and the environment.
```
$ cloudron exec
```
You can also execute arbitrary commands:
```
$ cloudron exec env # display the env variables that your app is running with
```
### Debugging
An app can be placed in `debug` mode by passing `--debug` to `cloudron install` or `cloudron configure`.
Doing so, runs the app in a non-readonly rootfs and unlimited memory. By default, this will also ignore
the `RUN` command specified in the Dockerfile. The developer can then interactively test the app and
startup scripts using `cloudron exec`.
This mode can be used to identify the files being modified by your application - often required to
debug situations where your app does not run on a readonly rootfs. Run your app using `cloudron exec`
and use `find / -mmin -30` to find file that have been changed or created in the last 30 minutes.
You can turn off debugging mode using `cloudron configure --no-debug`.
# Addons
## Filesystem
The application container created on the Cloudron has a `readonly` file system. Writing to any location
other than the below will result in an error:
* `/tmp` - Use this location for temporary files. The Cloudron will cleanup any files in this directory
periodically.
* `/run` - Use this location for runtime configuration and dynamic data. These files should not be expected
to persist across application restarts (for example, after an update or a crash).
* `/app/data` - Use this location to store application data that is to be backed up. To use this location,
you must use the [localstorage](/references/addons.html#localstorage) addon. For convenience, the initial CloudronManifest.json generated by
`cloudron init` already contains this addon.
## Database
Most web applications require a database of some form. In theory, it is possible to run any
database you want as part of the application image. This is, however, a waste of server resources
should every app runs it's own database server.
Cloudron currently provides [mysql](/references/addons.html#mysql), [postgresql](/references/addons.html#postgresql),
[mongodb](/references/addons.html#mongodb), [redis](/references/addons.html#redis) database addons. When choosing
these addons, the Cloudron will inject environment variables that contain information on how to connect
to the addon.
See https://git.cloudron.io/cloudron/tutorial-redis for a simple example of how redis can be used by
an application. The server simply uses the environment variables to connect to redis.
## Email
Cloudron applications can send email using the `sendmail` addon. Using the `sendmail` addon provides
the SMTP server and authentication credentials in environment variables.
Cloudron applications can also receive mail via IMAP using the `recvmail` addon.
## Authentication
The Cloudron has a centralized panel for managing users and groups. Apps can integrate Single Sign-On
authentication using LDAP or OAuth.
Apps can integrate with the Cloudron authentication system using LDAP, OAuth or Simple Auth. See the
[authentication](/references/authentication.html) reference page for more details.
See https://git.cloudron.io/cloudron/tutorial-ldap for a simple example of how to authenticate via LDAP.
For apps that are single user can skip Single Sign-On support by setting the `"singleUser": true`
in the manifest. By doing so, the Cloudron will installer will show a dialog to choose a user.
For app that have no user management at all, the Cloudron implements an `OAuth proxy` that
optionally lets the Cloudron admin make the app visible only for logged in users.
# Best practices
## No Setup
A Cloudron app is meant to instantly usable after installation. For this reason, Cloudron apps must not
show any setup screen after installation and should simply choose reasonable defaults.
Databases, email configuration should be automatically picked up from the environment variables using
addons.
## Docker
Cloudron uses Docker in the backend, so the package build script is a regular `Dockerfile`.
The app is run as a read-only docker container. Only `/run` (dynamic data), `/app/data` (backup data) and `/tmp` (temporary files) are writable at runtime. Because of this:
* Install any required packages in the Dockerfile.
* Create static configuration files in the Dockerfile.
* Create symlinks to dynamic configuration files under `/run` in the Dockerfile.
### Source directory
By convention, Cloudron apps install the source code in `/app/code`. Do not forget to create the directory for the code of the app:
```sh
RUN mkdir -p /app/code
WORKDIR /app/code
```
### Download archives
When packaging an app you often want to download and extract archives (e.g. from github).
This can be done in one line by combining `wget` and `tar` like this:
```docker
ENV VERSION 1.6.2
RUN wget "https://github.com/FreshRSS/FreshRSS/archive/${VERSION}.tar.gz" -O - \
| tar -xz -C /app/code --strip-components=1
```
The `--strip-components=1` causes the topmost directory in the archive to be skipped.
Always pin the download to a specific tag or commit instead of using `HEAD` or `master`
so that the builds are reasonably reproducible.
### Applying patches
To get the app working in Cloudron, sometimes it is necessary to patch the original sources. Patch is a safe way to modify sources, as it fails when the expected original sources changed too much.
First create a backup copy of the full sources (to be able to calculate the differences):
```sh
cp -a extensions extensions-orig
```
Then modify the sources in the original path and when finished, create a patch like this:
RUN patch -p1 -d /app/code/extensions < /app/code/change-ttrss-file-path.patch
```
The `-p1` causes patch to ignore the topmost directory in the patch.
## Process manager
Docker supports restarting processes natively. Should your application crash, it will be restarted
automatically. If your application is a single process, you do not require any process manager.
Use supervisor, pm2 or any of the other process managers if you application has more then one component.
This **excludes** web servers like apache, nginx which can already manage their children by themselves.
Be sure to pick a process manager that [forwards signals](#sigterm-handling) to child processes.
## Automatic updates
Some apps support automatic updates by overwriting themselves. A Cloudron app cannot overwrite itself
because of the read-only file system. For this reason, disable auto updates for app and let updates be
triggered through the Cloudron Store. This ties in better to the Cloudron's update and restore approach
should something go wrong with the update.
## Logging
Cloudron applications stream their logs to stdout and stderr. In practice, this ideal is hard to achieve.
Some programs like apache simply don't log to stdout. In those cases, simply log to `/tmp` or `/run`.
Logging to stdout has many advantages:
* App does not need to rotate logs and the Cloudron takes care of managing logs.
* App does not need special mechanism to release log file handles (on a log rotate).
* Integrates better with tooling like cloudron cli.
## Memory
By default, applications get 256MB RAM (including swap). This can be changed using the `memoryLimit`
field in the manifest.
Design your application runtime for concurrent use by 50 users. The Cloudron is not designed for
concurrent access by 100s or 1000s of users.
An app can determine it's memory limit by reading `/sys/fs/cgroup/memory/memory.limit_in_bytes`.
## Authentication
Apps should integrate with one of the [authentication strategies](/references/authentication.html).
This saves the user from having to manage separate set of credentials for each app.
## Start script
Many apps do not launch the server directly, as we did in our basic example. Instead, they execute
a `start.sh` script (named so by convention) which is used as the app entry point.
At the end of the Dockerfile you should add your start script (`start.sh`) and set it as the default command.
Ensure that the `start.sh` is executable in the app package repo. This can be done with `chmod +x start.sh`.
```docker
ADD start.sh /app/code/start.sh
CMD [ "/app/code/start.sh" ]
```
### One-time init
One common pattern is to initialize the data directory with some commands once depending on the existence of a special `.initialized` file.
```sh
if ! [ -f /app/data/.initialized ]; then
echo "Fresh installation, setting up data directory..."
# Setup commands here
touch /app/data/.initialized
echo "Done."
fi
```
To copy over some files from the code directory you can use the following command:
```sh
rsync -a /app/code/config/ /app/data/config/
```
### chown data files
Since the app containers use other user ids than the host, it is sometimes necessary to change the permissions on the data directory:
```sh
chown -R cloudron.cloudron /app/data
```
For Apache+PHP apps you might need to change permissions to `www-data.www-data` instead.
### Persisting random values
Some apps need a random value that is initialized once and does not change afterwards (e.g. a salt for security purposes). This can be accomplished by creating a random value and storing it in a file in the data directory like this:
Addon information (mail, database) exposed as environment are subject to change across restarts and an application must use these values directly (i.e not cache them across restarts). For this reason, it usually regenerates any config files with the current database settings on each invocation.
First create a config file template like this:
```sh
... snipped ...
'mysql' => array(
'driver' => 'mysql',
'host' => '##MYSQL_HOST',
'port' => '##MYSQL_PORT',
'database' => '##MYSQL_DATABASE',
'username' => '##MYSQL_USERNAME',
'password' => '##MYSQL_PASSWORD',
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
),
... snipped ...
```
Add the template file to the Dockerfile and create a symlink to the dynamic configuration file as follows:
bash, by default, does not automatically forward signals to child processes. This would mean that a SIGTERM sent to the parent processes does not reach the children. For this reason, be sure to `exec` as the
last line of the start.sh script. Programs like gosu, nginx, apache do proper SIGTERM handling.
For example, start apache using `exec` as below:
```sh
echo "Starting apache"
APACHE_CONFDIR="" source /etc/apache2/envvars
rm -f "${APACHE_PID_FILE}"
exec /usr/sbin/apache2 -DFOREGROUND
```
## Popular stacks
### Apache
Apache requires some configuration changes to work properly with Cloudron. The following commands configure Apache in the following way:
* Disable all default sites
* Print errors into the app's log and disable other logs
* Limit server processes to `5` (good default value)
* Change the port number to Cloudrons default `8000`
```docker
RUN rm /etc/apache2/sites-enabled/* \
&& sed -e 's,^ErrorLog.*,ErrorLog "/dev/stderr",' -i /etc/apache2/apache2.conf \
&& sed -e "s,MaxSpareServers[^:].*,MaxSpareServers 5," -i /etc/apache2/mods-available/mpm_prefork.conf \
In `start.sh` Apache can be started using these commands:
```sh
echo "Starting apache..."
APACHE_CONFDIR="" source /etc/apache2/envvars
rm -f "${APACHE_PID_FILE}"
exec /usr/sbin/apache2 -DFOREGROUND
```
### PHP
PHP wants to store session data at `/var/lib/php/sessions` which is read-only in Cloudron. To fix this problem you can move this data to `/run/php/sessions` with these commands:
```docker
RUN rm -rf /var/lib/php/sessions && ln -s /run/php/sessions /var/lib/php/sessions
```
Don't forget to create this directory and it's ownership in the `start.sh`:
```sh
mkdir -p /run/php/sessions
chown www-data:www-data /run/php/sessions
```
### Java
Java scales its memory usage dynamically according to the available system memory. Due to how Docker works, Java sees the hosts total memory instead of the memory limit of the app. To restrict Java to the apps memory limit it is necessary to add a special parameter to Java calls.
The Cloudron Store is a mechanism to share your app with others who use Cloudron. Currently, to ensure that
apps are maintained, secure and well supported there are some restrictions imposed on apps submitted to
the Cloudron Store. See [#292](https://git.cloudron.io/cloudron/box/issues/292) and [#327](https://git.cloudron.io/cloudron/box/issues/327) for an in-depth discussion.
The following criteria must be met before submitting an app for review:
* You must be willing to relocate your app packaging code to the [Cloudron Git Repo](https://git.cloudron.io/cloudron/).
* Contributed apps must have browser tests. You can see the various [app repos](https://git.cloudron.io/cloudron/) to get an idea on how to write these tests. The Cloudron team can help you write the tests.
* For all practical purposes, you are the maintainer of the app and Cloudron team will not commit to the repo
directly. Any changes will be submitted as Merge Requests.
* You agree that the Cloudron team can take over the responsibility of progressing the app further if you become unresponsive (48 hours), lose interest, lack time etc. Please send us an email if your priorities change.
* You must sign the [Cloudron CLA](https://cla.cloudron.io/).
As a token of our appreciation, 3rd party app authors can use the Cloudron for personal or business use for free.
## Upload for Testing
Once your app is ready, you can upload it to the store for `beta testing` by
other Cloudron users. This can be done using:
```
cloudron appstore upload
```
You should now be able to visit `/#/appstore/<appid>?version=<appversion>` on your
Cloudron to check if the icon, description and other details appear correctly.
Other Cloudron users can install your app on their Cloudron's using
`cloudron install --appstore-id <appid@version>`.
## Publishing
Once you are satisfied with the beta testing, you can submit it for review.
```
cloudron appstore submit
```
The cloudron.io team will review the app and publish the app to the store.
## Versioning and Updates
To create an update for an app, simply bump up the [semver version](/references/manifest.html#version) field in
the manifest and publish a new version to the store.
The Cloudron chooses the next app version to update to based on the following algorithm:
* Choose the maximum `patch` version matching the app's current `major` and `minor` version.
* Failing the above, choose the maximum patch version of the next minor version matching the app's current `major` version.
* Failing the above, choose the maximum patch and minor version of the next major version
For example, let's assume the versions 1.1.3, 1.1.4, 1.1.5, 1.2.4, 1.2.6, 1.3.0, 2.0.0 are published.
* If the app is running 1.1.3, then app will directly update to 1.1.5 (skipping 1.1.4)
* Once in 1.1.5, the app will update to 1.2.6 (skipping 1.2.4)
* Once in 1.2.6, the app will update to 1.3.0
* Once in 1.3.0, the app will update to 2.0.0
The Cloudron admins get notified by email for any major or minor app releases.
## Failed updates
The Cloudron always makes a backup of the app before making an update. Should the
update fail, the user can restore to the backup (which will also restore the app's
code to the previous version).
# Cloudron Button
The [Cloudron Button](/references/button.html) allows anyone to install your application with the click of a button
on their Cloudron.
The button can be added to just about any website including the application's website
and README.md files in GitHub repositories.
# Next steps
Congratulations! You are now well equipped to build web applications for the Cloudron.
You can see some examples of how real apps are packaged here:
db.runSql('ALTER TABLE apps DROP INDEX location_domain_unique_index, DROP FOREIGN KEY apps_domain_constraint, DROP COLUMN domain, DROP COLUMN location, DROP COLUMN dnsRecordId',function(error){
if(error)console.error(error);
callback(error);
});
};
exports.down=function(db,callback){
db.all('SELECT * from subdomains WHERE type = ?',['primary'],function(error,results){
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.