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
lastBackupId is only used as a "message" passing field for apptask restore.
Theoretically, this code somehow protects a race between the cleanup logic
and the restore apptask. this is unlikely to happen and adds unnecessary
complexity.
This is sometimes useful when an update gets stuck because of some
bug in backup logic.
Note that you cannot restore from this backend because nothing is
saved.
Starting them all at once, sometimes hogs cpu/memory too much
and makes the startup scripts of the addons error.
The new addons setup a .setup file to confirm initialization.
In a future commit, we can use those .setup files to check if
the addon has started up instead of a timeout
This easy fix should improve performance with newer browsers especially
for applications that require many files to be sent over the wire
*cough*Nextcloud11*cough*
NGINX blog post about HTTP/2 support: https://www.nginx.com/blog/nginx-1-9-5/
This gets the right error message on failures:
$ cloudron machine backup create
Waiting for backup to finish...backup failed: ENOENT: no such file or directory, open '/var/backups/2017-04-21-013900-584/app_7549c6a1-682e-4150-8b40-2c31a3fa92f7_2017-04-21-013900-591_v0.7.1.tar.gz'
This is the root cause of 926224bd5d.
0488aada9f caused a regression where
we setup addons in the restore code path. This meant that redis was
instantiated and running, changing the perms of the dir. Then when
the backup extract happens it fails as it has wrong permissions.
All Cloudron containers need to have the nameserver 172.18.0.1. This was
being done at the daemon level, however since there are also iptables
rules restricting access to the nameserver from containers that aren't
on the Cloudron Docker network, this broke DNS for non-Cloudron
containers.
Since the DNS is only required for Cloudron containers in the first
place, this patch specifies 172.18.0.1 as the nameserver when Cloudron
creates a container and reverts the change at the daemon level
Those are not mocked yet and require real aws things.
Change will follow for mocking. We should probably keep them optionally
working agains AWS directly to ensure things really work
This is only temporarily as moving away from btrfs snapshots,
we introduced a regression for app backups.
gnu tar fails to create tarballs if the files change during packing.
Explanation:
When proxying an HTTP request, nginx first fills up the memory buffers (set by proxy_buffer_size and proxy_buffers).
When these are full, it then writes them to a temporary file in batches of proxy_temp_file_write_size until it reaches proxy_max_temp_file_size.
When proxy_max_temp_file_size is not set, and a very large file is being served, it reaches the maximum of 1GB, and nginx begins to behave weirdly.
Sometimes on error we get random strings for the installationProgresss,
as those contain the upstream errors :-/
We now at least attempt to show that so the user may give us the real
error not some wrongly parsed bits from that.
In the long run we have to make that a real structure to give sane error
messages
The goal here is to simply add a rate limit to prevent brute
force password attacks.
Covered services includes:
(public) http, https, ssh, smtp, msa, imap, sieve
(private) postgres, redis, mysql, ldap, mongodb. msa
The private limits are higher because some apps will create
a db connection for each page request. Some apps like mailtrain
will send out lots of emails etc.
Note that apps that use SSO are ratelimited by the ldap limit.
Part of #187
Also remove rate-limit middleware
Test using something like:
ab -v 1 -n 1000 -c 10 -s 5 -m POST https://my.<doamain>/api/v1/developer/login
Part of #187
some disk types do not contain proper partition tables like on time4vps
the type is simfs. On those fdisk fails to access the partition table,
thus being unable to determine the size of the volume.
df does only return the real usable disk space by the user, thus we
lower the 20GB threshold to 18
Fixes#275
Apps like nextcloud set their own security headers ending up with having
them set twice. I am not 100% sure if our headers should win or if we
should not inject headers with nginx if the upstream app sets them already.
This looks like the more permissive case where we simply enforce our
values, regardless what the apps sets.
This also fixes the nextcloud/owncloud security checks which were
failing because the header values were duplicated, which results in
string concatenation of values from same headers.
Simple Auth used to provide auth over HTTP. The original motivation
behind this was this was a simple way to add Cloudron Auth integration.
Back in the day, Cloudron Auth was a requirement for apps but this is
not the case anymore.
This is currently not used by any app and having this might encourage
people to make Cloudron specific un-upstreamable changes.
This is required for the case where the box restarts apptasks.
For example, the server can reboot mid-way when apptask is running
(as in cloudron-setup + appBundle case) and then when it comes back
up it doesn't wait for the platform to be ready. And the apps fail
to install (mysql takes a bit to startup)
This is based on the existence of admin.conf nginx file.
The splash would create/overwrite that file, but it will depend on the
host.cert to be already created, which is only the case after domain
setup.
We have 4 properties related to the domain:
1) location, is the subdomain location without information how to craft
a fqdn on the client
2) fqdn, the intended domain to reach the app
3) altDomain, just the value for the external domain, merely a db record
value
4) cnameTarget, mostly for display purpose on the client, which
otherwise has no way to build the original cloudron local fqdn
The configure code path now ensures the volume which ends up
changing the ownership of the data directory. This means that the
redis container which is still running cannot write anymore
when it is re-created as part of setupAddons().
Just change ownership of top level directory. The subdirectores
like data/ redis/ are owned by containers which will chown
accordingly.
For some reason, docker devices are collected in collectd stats (despite
us collecting only ext4 and btrfs devices). They have the patter *docker*.
Fixes#222
mocha loads all the tests in same process. This means that when
we start a new test, the old state still persists. For event
listeners, this means that they get multiple duplicate event handlers.
This will anyways happen once a new EC2 instance is created from the ami
and this ensures we do not encounter an SSH disconnect error when
running the cloudron-setup script during image creation
We use only mysql, so updating this means a lot of unused db backends
like sqlite do not need to be built with gyp anymore.
Note that this version is not yet released as stable, but works fine for
us. The outstanding issues are not related to our use-case from what I
can tell.
Fixes#82
This is then in sync with selfhosting and ensures the init startup
sequence is in order, since the setup on its own creates unit files
which should run prior to services already running.
This hopefully fixes the mysql disconnect issues.
This prevents one from redirecting to some http-only subdomain.
For example, surfer in naked domain redirects to www subdomain
(which is on github pages...)
/tmp is not very secure. But the real reason is so that we can
re-run the setup script again should things fail.
/home/yellowtent/box/scripts/installer.sh --data-file /root/cloudron-update-data.json
The following packages will be DOWNGRADED:
docker-engine
0 upgraded, 0 newly installed, 1 downgraded, 0 to remove and 0 not upgraded.
E: Packages were downgraded and -y was used without --allow-downgrades.
The core issue we want to solve is to debug a running app.
Let's make it explicit that it is in debugging mode because
functions like update/backup/restore don't work.
Part of #171
This is as reporting the disk size may vary from the one selected when
creating the server. Eg EC2 20GB storage results in 21474836480 bytes
which in turn will be calculated as less than 20GB in the script
When turned off, it will put the app in a writable rootfs. This
allows us to debug live/production apps (like change start.sh) and
just get them up and running. Once turned off, this app cannot be
updated anymore (unless the force flag is set). This way we can
then update it using the CLI if we are convinced that the upcoming
update fixes the problem.
Part of #171
Using the bytes output will fix an issue where the disk size is reported
either as terrabyte or also megabyte.
So far we disallowed 1TB disks but allowed 20MB disks.
file mounting is fraught with problems wrt change notifications.
first, we must be carefule that the inode does not change.
second, changes outside container do not result in fs events inside the container.
haraka cache settings files and relies on fs events. So, even
though the file gets updated inside the container, haraka doesn't
see it.
https://github.com/docker/docker/issues/15793
We had all this logic because we allowed the user to create a CaaS
cloudron with a custom domain from the appstore. This flow has changed
now.
One can only set the DNS config after verification. Only thing that
is required is a domain check.
Because of the docker upgrade, dnsbl queries are failing again
since we are not using the unbound server from the containers.
For some reason, docker cannot query 127.0.0.1 (https://github.com/docker/docker/issues/14627).
Make unbound listed on the cloudron network and let docker proxy
DNS calls to unbound (docker always use the embedded DNS server
when using UDN).
See also #130
One idea was to use docker binary packages. However, docker binaries
are statically linked and are incompatible with devicemapper.
See https://github.com/docker/docker/issues/14035 for more info.
Holding will let the user turn on automatic updates for non-security
packages as well.
Fixes#183
When docker is not passed the --storage-driver option, it tries to
auto detect the storage driver. Roughly:
1. If existing storage paths like /var/lib/docker/aufs exist, it will
choose that driver.
2. It has a priority list of drivers to scan in order (driver.go)
As it stands the ordering is aufs, btrfs and then devicemapper.
3. Docker will attempt to "init" each driver. aufs, for example,
tests for insmod'ing aufs and also looks into /proc/filesystems.
The fact that we installed aufs-tools and linux drivers (for aufs
driver) was a programming error since we want docker to use devicemapper.
However, what is curious is why docker still ended up choosing devicemapper
despite having all aufs requirements (as we do not pass --storage-driver explicitly).
The answer is that "apt-get install aufs-tool linux-image-* docker-engine"
can install packages in any order! This means there is a race on how docker
chooses the storage engine. In most cases, since linux-image-* is a big package,
docker gets to install first and ends up using devicemapper since aufs module is not found yet.
For some people, linux-image-* possibly installs first and thus docker
chooses aufs!
Mystery solved.
Part of #183
For reasons unknown, the images build by the buildbot (which currently
uses btrfs), does not work with devicemapper.
Existing cloudrons with aufs will not be affected because docker will
just ignore it.
devmapper: Base device already exists and has filesystem xfs on it. User specified filesystem will be ignored.
Existing AUFS users can move to devicemapper either by restoring to
a new cloudron (recommended) OR
* systemctl stop box
* systemctl stop docker
* rm -rf /var/lib/docker
* Edit /home/yellowtent/data/INFRA_VERSION. Change the "version" field to "1"
* systemctl start docker
* systemctl start box # this will download images all over
Fixes#182
If we change the domain when dns settings are changed, then migration
fails because we callout to appstore API via the domain (for example,
backup url call will fail because it uses the new domain name).
appbackup_%s_%s-v%s.tar.gz -> app_%s_%s_v%s.tar.gz
drop 'backup'. rationale: it is known these files are backups
timestamp has '-'. rationale: colon in filename confuses tools like scp (they think it is a hostname)
backup_%s-v%s.tar.gz -> box_%s_v%s.tar.gz
drop 'backup' and name it 'box'. this makes it clear it related to the box backup
timestamp has '-'. rationale: colon in filename confuses tools like scp (they think it is a hostname)
Part of #159
Since we don't have cases like failing to charge credit card so far, the
only reason it can fail here is that the appstore token or userId is
incorrect/expired
Fixes#52
This redesigns how update works. installer.sh now rebuild the package,
stops the old code and starts the new code. Importantly, it does not
download the new package, this is left to the caller. cloudron-setup
downloads the code and calls installer.sh of the downloaded code.
Same goes for updater.sh. This means that installer.sh itself is now
easily updatable.
Part of #152
Docker uses an embedded DNS server (127.0.0.11) for user defined networks (UDN).
With the latest releases of docker, specifying 127.0.0.1 as --dns makes the
containers resolve 127.0.0.1 _inside_ the container's networking namespace
(not sure how it worked before this).
The next idea was to only specify --dns-search=. but this does not work.
This makes docker setup the containers to use 127.0.0.1 (or 127.0.0.11 for UDN).
In my mind, the UDN case should work but doesn't (not sure why).
So, the solution is to simply go with no --dns or --dns-search. Sadly,
setting dns-search just at container level does not work either :/ Strangely,
docker run --network=cloudron --dns-search=. appimage # does not work
docker run --network=cloudron appimage # works if you manually remove search from /etc/resolv.conf
So clearly, something inside docker triggers when one of the dns* options is set.
This means that #130 has to be fixed at app level (For Go, this means to use the cgo resolver).
The new DO images have a different label causing DO images to not boot
root@ubuntu-2gb-sfo1-01:~# e2label /dev/vda1
cloudimg-rootfs
net.ifnames=0 is used get unpredictable names as per
https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/.
Not sure why we want that.
Not sure about notsc and clocksource.
This change also preserves any existing cmdline
This is unused. But more importantly, it causes the cloudron to
internal error and the whole UI goes down just because we cannot
detect the IP via the generic sysinfo provider.
This code was here to check if user will get an admin certificate.
It doesn't work well for intranet cloudron's. The check is also not
complete since just DNS is not enough for LE to succeed, we also
require port forwarding.
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://github.com/cloudron-io/omniauth-cloudron) and Node.js [passport](https://github.com/cloudron-io/passport-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
@@ -317,68 +317,3 @@ cloudron exec
> swaks --server "${MAIL_SMTP_SERVER}" -p "${MAIL_SMTP_PORT}" --from "${MAIL_SMTP_USERNAME}@${MAIL_DOMAIN}" --body "Test mail from cloudron app at $(hostname -f)" --auth-user "${MAIL_SMTP_USERNAME}" --auth-password "${MAIL_SMTP_PASSWORD}"
```
## simpleauth
Simple Auth can be used for authenticating users with a HTTP request. This method of authentication is targeted
at applications, which for whatever reason can't use the ldap addon.
The response contains an `accessToken` which can then be used to access the [Cloudron API](/references/api.html).
Exported environment variables:
```
SIMPLE_AUTH_SERVER= # the simple auth HTTP server
SIMPLE_AUTH_PORT= # the simple auth server port
SIMPLE_AUTH_URL= # the simple auth server URL. same as "http://SIMPLE_AUTH_SERVER:SIMPLE_AUTH_PORT
SIMPLE_AUTH_CLIENT_ID # a client id for identifying the request originator with the auth server
```
This addons provides two REST APIs:
**POST /api/v1/login**
Request JSON body:
```
{
"username": "<username> or <email>",
"password": "<password>"
}
```
Response 200 with JSON body:
```
{
"accessToken": "<accessToken>",
"user": {
"id": "<userId>",
"username": "<username>",
"email": "<email>",
"admin": <admin boolean>,
"displayName": "<display name>"
}
}
```
**GET /api/v1/logout**
Request params:
```
?access_token=<accessToken>
```
Response 200 with JSON body:
```
{}
```
For debugging, [cloudron exec](https://www.npmjs.com/package/cloudron) can be used to run the `curl` tool within the context of the app:
OAuth authentication is meant to be used by apps. An app can get an OAuth token using the
[oauth](addons.html#oauth) or [simpleauth](addons.html#simpleauth) addon.
[oauth](addons.html#oauth) addon.
Tokens obtained via OAuth have a restricted scope wherein they can only access the user's profile.
This restriction is so that apps cannot make undesired changes to the user's Cloudron.
@@ -117,6 +117,7 @@ Request:
cert: <string>, // pem encoded TLS cert
key: <string>, // pem encoded TLS key
memoryLimit: <number>, // memory constraint in bytes
backupId: <string>, // initialize the app from this backup
altDomain: <string>, // alternate domain from which this app can be reached
xFrameOptions: <string> // set X-Frame-Options header, to control which websites can embed this app
}
@@ -151,6 +152,10 @@ If `altDomain` is set, the app can be accessed from `https://<altDomain>`.
*`SAMEORIGIN` - allows embedding from the same domain as the app. This is the default.
*`ALLOW-FROM https://example.com/` - allows this app to be embedded from example.com
`memoryLimit` is the maximum memory this app can use (in bytes) including swap. If set to 0, the app uses the `memoryLimit` value set in the manifest. If set to -1, the app gets unlimited memory.
If `backupId` is provided the app will be initialized with the data from the backup.
Read more about the options at [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).
Response (200):
@@ -197,7 +202,8 @@ Response (200):
health: <enum>, // health of the application
location: <string>, // subdomain on which app is installed
fqdn: <string>, // the FQDN of this app
altDomain: <string> // alternate domain from which this app can be reached
altDomain: <string>, // alternate domain from which this app can be reached
cnameTarget: <string> || null, // If altDomain is set, this contains the CNAME location for the app
accessRestriction: null || { // list of users and groups who can access this application
users: [ ],
groups: [ ]
@@ -207,7 +213,8 @@ Response (200):
portBindings: { // mapping from application ports to public ports
},
iconUrl: <url>, // a relative url providing the icon
memoryLimit: <number> // memory constraint in bytes
memoryLimit: <number>, // memory constraint in bytes
sso: <boolean> // Enable single sign-on
}
```
@@ -255,6 +262,8 @@ is integrated with Cloudron Authentication.
`manifest` is the [application manifest](/references/manifest.html).
For apps that support optional single sign-on, the `sso` field can be used to disable Cloudron authentication. By default, single sign-on is enabled.
### List apps
GET `/api/v1/apps/:appId` <scope>admin</scope>
@@ -276,7 +285,8 @@ Response (200):
health: <enum>, // health of the application
location: <string>, // subdomain on which app is installed
fqdn: <string>, // the FQDN of this app
altDomain: <string> // alternate domain from which this app can be reached
altDomain: <string>, // alternate domain from which this app can be reached
cnameTarget: <string> || null, // If altDomain is set, this contains the CNAME location for the app
accessRestriction: null || { // list of users and groups who can access this application
users: [ ],
groups: [ ]
@@ -447,7 +457,7 @@ POST `/api/v1/apps/:appId/configure` <scope>admin</scope>
Re-configures an existing app with id `appId`.
Configuring an app won't preserve existing data. Cloudron apps are written in a way to support reconfiguring
Configuring an app preserves existing data. Cloudron apps are written in a way to support reconfiguring
any of the parameters listed below without loss of data.
monotonicTimestamp: <number>, // time passed since boot
message: [ <byte>,... ], // utf8 buffer
source: <process name> // source of this message
}
```
### List events
GET `/api/v1/eventlog` <scope>admin</scope>
GET `/api/v1/cloudron/eventlog` <scope>admin</scope>
Lists all the past events.
@@ -804,13 +900,13 @@ Response (200):
* user.remove
* user.update
`source` contains information on the originator of the action. For example, for user.login, this contains the IP address, the appId and the authType (ldap or simpleauth or oauth).
`source` contains information on the originator of the action. For example, for user.login, this contains the IP address, the appId and the authType (ldap or oauth).
`data` contains information on the event itself. For example, for user.login, this contains the userId that logged in. For app.install, it contains the manifest and location of the app that was installed.
To list all the app installation events:
```
curl -X GET -H 'Authorization: Bearer cb0463455a6606482be7956fc3abd53330ae23244e3492cda3914a2c5154c47e' https://my-demo.cloudron.me/api/v1/eventlog?action=app.install
curl -X GET -H 'Authorization: Bearer cb0463455a6606482be7956fc3abd53330ae23244e3492cda3914a2c5154c47e' https://my-demo.cloudron.me/api/v1/cloudron/eventlog?action=app.install
```
## Groups
@@ -964,25 +1060,37 @@ Response (204):
{}
```
### Tutorial
## Settings
POST `/api/v1/profile/tutorial` <scope>profile</scope>
### Get Appstore Config
Toggles display of the tutorial when the token owner logs in.
GET `/api/v1/settings/appstore_config` <scope>admin</scope>
Response (200):
```
{
userId: <string>, // the appstore userId
token: <string>, // appstore token
cloudronId: <string> // cloudron id
}
```
### Set Appstore Config
POST `/api/v1/settings/appstore_config` <scope>admin</scope>
Sets the credentials used for the Cloudron Store.
Request:
```
{
showTutorial: <boolean>
userId: <string>, // the appstore userId
token: <string> // token from appstore
}
```
Response (204):
```
{}
```
## Settings
You can get the `userId` and `token` by sending a `/api/v1/login` POST request to `api.cloudron.io`
with the `email` and `password` fields set in the request.
### Get auto update pattern
@@ -1088,6 +1196,34 @@ Request:
}
```
### Get Catch All Address
GET `/api/v1/settings/catch_all_address` <scope>admin</scope>
Gets the address(es) to which emails addressed to a non-existent mailbox are forwarded to.
Configuring a catch-all address can help avoid losing emails due to misspelling.
Response(200):
```
{
"address": [ <string> ] // array of mailbox names
}
```
### Set Catch All Address
PUT `/api/v1/settings/catch_all_address` <scope>admin</scope>
Sets the address(es) to which emails addressed to a non-existent mailbox are forwarded.
Configuring a catch-all address can help avoid losing emails due to misspelling.
Request:
```
{
"address": [ <string> ] // array of mailbox names
}
```
### Get DNS Configuration
GET `/api/v1/settings/dns_config` <scope>admin</scope> <scope>internal</scope>
@@ -1099,7 +1235,7 @@ This is currently internal API and is documented here for completeness.
Response(200):
```
{
"provider": <string> // 'caas' or 'route53' or 'digitalocean'
"provider": <string> // 'caas' or 'route53' or 'digitalocean' or 'noop' or 'manual'
}
```
@@ -1113,7 +1249,7 @@ This is currently internal API and is documented here for completeness.
### Get Email Configuration
GET `/api/v1/settings/mail_config` <scope>admin</scope> <scope>internal</scope>
GET `/api/v1/settings/mail_config` <scope>admin</scope>
Gets the email configuration. The Cloudron has a built-in email server for users.
This configuration can be used to disable the server. Note that the Cloudron will
@@ -1128,11 +1264,11 @@ Response(200):
### Set Email Configuration
POST `/api/v1/settings/mail_config` <scope>admin</scope> <scope>internal</scope>
POST `/api/v1/settings/mail_config` <scope>admin</scope>
Sets the email configuration. The Cloudron has a built-in email server for users.
This configuration can be used to enable or disable the email server. Note that
the Cloudron will always be able to send email on behalf of apps, regardless of
the Cloudron will always be able to send email on behalf of apps, regardless of
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
@@ -260,22 +249,61 @@ reputation should be easy to get back.
## Checklist
*Once your Cloudron is ready, setup a Reverse DNS PTR record to be setup for the `my` subdomain.
*If you are unable to receive mail, first thing to check is if your VPS provider lets you
receive mail on port 25.
*AWS/EC2 - Fill the PTR [request form](https://aws-portal.amazon.com/gp/aws/html-forms-controller/contactus/ec2-email-limit-rdns-request.
*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>`.
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).
*Scaleway - Edit your security group to allow email. You can also set a PTR record on the interface with your
`my.<domain>`.
*Linode - Follow this [guide](https://www.linode.com/docs/networking/dns/setting-reverse-dns).
* Check if your IP is listed in any DNSBL list [here](http://multirbl.valli.org/). In most cases,
you can apply for removal of your IP by filling out a form at the DNSBL manager site.
* 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.
@@ -292,24 +320,26 @@ case an update fails, it can be [restored](/references/selfhosting.html#restore)
### Upgrade
An **upgrade** requires a new OS image and thus involves creating the Cloudron from scratch.
This process involves creating a new server with the latest code and restoring it from the
last backup. Currently only Cloudrons using the **S3 backup storage** support upgrades.
Read more about [backup storage](#s3), otherwise contact us in our [chat](https://chat.cloudron.io).
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 <domain>`
* Create a new backup - `cloudron machine backup create`
* List the latest backup - `cloudron machine backup list <domain>`
* List the latest backup - `cloudron machine backup list`
* Make the latest box backup (files starting with `backup_`) public. This can be done from the AWS S3 console as seen here:
* Make the backup available for the new cloudron instance:
*`S3` - When storing backup ins S3, make the latest box backuppublic - files starting with `box_` (from v0.94.0) or `backup_`. This can be done from the AWS S3 console as seen here:
* Copy the new public URL of the latest backup for use as the `--restore-url` below.
*`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.
@@ -318,29 +348,147 @@ To upgrade follow these steps closely:
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 <domain>`
* Select the backup - `cloudron machine backup list`
* Make the box backup public (this can be done from the S3 console). Also, copy the URL of
the backup for use as the `restore-url` below.
* 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`, `restore-key` and `restore-url` flags.
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.
@@ -349,6 +497,14 @@ You can SSH into your Cloudron and collect logs:
*`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).
@@ -188,7 +188,7 @@ Build scheduled with id e7706847-f2e3-4ba2-9638-3f334a9453a5
Waiting for build to begin, this may take a bit...
Downloading source
Building
Step 1 : FROM cloudron/base:0.9.0
Step 1 : FROM cloudron/base:0.10.0
---> be9fc6312b2d
Step 2 : ADD server.js /app/code/server.js
---> 10513e428d7a
@@ -271,14 +271,18 @@ You can also execute arbitrary commands:
$ cloudron exec env # display the env variables that your app is running with
```
### DevelopmentMode
### Debugging
When debugging complex startup scripts, one can specify `"developmentMode": true,` in the CloudronManifest.json.
This will ignore the `RUN` command, specified in the Dockerfile and allows the developer to interactively test
the startup scripts using `cloudron exec`.
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`.
**Note:** that an app running in this mode has full read/write access to the filesystem and all memory limits are lifted.
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
@@ -344,12 +348,64 @@ show any setup screen after installation and should simply choose reasonable def
Databases, email configuration should be automatically picked up from the environment variables using
addons.
## Dockerfile
## Docker
The app is run as a read-only docker container. 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.
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
@@ -358,7 +414,7 @@ automatically. If your application is a single process, you do not require any p
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 to child processes.
Be sure to pick a process manager that [forwards signals](#sigterm-handling) to child processes.
## Automatic updates
@@ -385,40 +441,214 @@ 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.
## Startup Script
## 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 launches the server. Before starting the server,
the `start.sh` script does the following:
a `start.sh` script (named so by convention) which is used as the app entry point.
* When using the `localstorage` addon, it changes the ownership of files in `/app/data` as desired using `chown`. This
is necessary because file permissions may not be correctly preserved across backup, restore, application and base image
updates.
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" ]
```
* 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.
### One-time init
* Finally, it starts the server as a non-root user.
One common pattern is to initialize the data directory with some commands once depending on the existence of a special `.initialized` file.
The app's main process must handle SIGTERM and forward it as required to child processes. bash does not
automatically forward signals to child processes. For this reason, when using a startup shell script,
remember to use exec <app> as the last line. Doing so will replace bash with your program and allows
your program to handle signals as required.
```sh
if ! [ -f /app/data/.initialized ]; then
echo "Fresh installation, setting up data directory..."
# Setup commands here
touch /app/data/.initialized
echo "Done."
fi
```
# Beta Testing
To copy over some files from the code directory you can use the following command:
## Metadata
```sh
rsync -a /app/code/config/ /app/data/config/
```
Publishing to the Cloudron Store requires apps to have meta data specified in the `CloudronManifest.json`.
### chown data files
The `cloudron` tool will notify if any such information is missing, prior to uploading.
See more information for each field [here](/references/manifest.html).
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
@@ -426,29 +656,26 @@ 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 upload
cloudron appstore upload
```
The app should now be visible in the Store view of your cloudron under
the 'Testing' section. You can check if the icon, description and other details
appear correctly.
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
## Publishing
Once you are satisfied with the beta testing, you can submit it for review.
```
cloudron submit
cloudron appstore submit
```
The cloudron.io team will review the app and publish the app to the store.
# Updating the app
## Versioning
## 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.
echo"Resizing up btrfs user data to size ${home_data_size}M"
umount "${USER_DATA_DIR}"||true
# Do not preallocate (non-sparse). Doing so overallocates for data too much in advance and causes problems when using many apps with smaller data
# fallocate -l "${home_data_size}m" "${USER_DATA_FILE}" # does not overwrite existing data
truncate -s "${home_data_size}m""${USER_DATA_FILE}"# this will shrink it if the file had existed. this is useful when running this script on a live system
mount -t btrfs -o loop,nosuid "${USER_DATA_FILE}"${USER_DATA_DIR}
echo"Showing progress bar on all subdomains in retired mode or infra update. retire: ${arg_retire_reason} existing: ${existing_infra} current: ${current_infra}"
# keep-alive connections timeout in 65s. this is because many browsers timeout in 60 seconds
keepalive_timeout65s;
# zones for rate limiting
limit_req_zone$binary_remote_addrzone=admin_login:10mrate=10r/s;# 10 request a second
# HTTP server
server{
listen80;
@@ -48,7 +51,7 @@ http {
# acme challenges
location/.well-known/acme-challenge/{
default_typetext/plain;
alias/home/yellowtent/data/acme/;
alias/home/yellowtent/platformdata/acme/;
}
location/{
@@ -57,35 +60,5 @@ http {
}
}
# This server handles the naked domain for custom domains.
# It can also be used for wildcard subdomain 404. This feature is not used by the Cloudron itself
# because box always sets up DNS records for app subdomains.
server{
listen443default_server;
sslon;
ssl_certificatecert/host.cert;
ssl_certificate_keycert/host.key;
error_page404=@fallback;
location@fallback{
internal;
root/home/yellowtent/box/webadmin/dist;
rewrite^/$ /nakeddomain.htmlbreak;
}
location/{
internal;
root/home/yellowtent/box/webadmin/dist;
rewrite^/$ /nakeddomain.htmlbreak;
}
# required for /api/v1/cloudron/avatar
location/api/{
proxy_passhttp://127.0.0.1:3000;
client_max_body_size1m;
}
}
includeapplications/*.conf;
}
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.