CalDav on DreamHost Shared Hosting | Feb 2022
Dreamhost natively supports WebDav for file synchronization but does not support CalDav unless you're on dedicated servers or their "dreamcompute" servers (which require you to configure everything).
This is just regarding Apache's mod_dav
module. You CAN get CalDav working through a regular webserver, using Sabre Dav, or probably other software too, if you don't want PHP.
Setup is pretty easy once you know what's going on.
Useful Info & Links
- Sabre Dav: The PHP software that makes this work. SabreDav Github
-
Sabre Authentication page for changing away from the default username/password of
admin/admin
- Sabre CalDav Setup Page for info about database access & which caldav urls to use
- from SSH on your dreamhost server,
cat ~/logs/dav.yourdomain.com/https/error.log
to see errors - There's a lot of useful links and documentation on the sabre dav site ... check those out if you need more help.
-
sqlite3 data/db.sqlite
should let you access the local database to add/remove users, when you're done using the default admin user.
Known Issues
- This tutorial uses the default user
admin
and default passwordadmin
that comes pre-setup with Sabre. - DH's
mod_security
config blocks thetext/calendar
content type, among other parts of the request for CalDav. You must disableExtra Web Security
to fix this, which may be a security risk. - Pushing changes to the server may delete any calendar events and users you have saved, so don't add much til you're done setting up everything.
- the password hashing uses
md5()
instead of password hash functions. See this issue discussing it
Configure DreamHost
- Create a new domain (or subdomain) with a new user, and enable
https
- Disable 'Extra Web Security'
- Use php 7.4 (at time of writing)
Install SabreDav
See official install instructions for more info.
- On your development machine, make a new folder like
dav.mywebsite.com
, then cd into it. -
composer require sabre/dav ~3.2.0
-
composer update sabre/dav
-
cp vendor/sabre/dav/examples/groupwareserver.php server.php
to copy the sample server file that includes CalDav and CardDav support. - edit
server.php
: uncomment the$baseUri
line (line 27), and add$authBackend->setRealm('SabreDav');
to line 69. (realm is used for password hashing) - mkdir
data/
-
cat vendor/sabre/dav/examples/sql/sqlite.* | sqlite3 data/db.sqlite
-
chmod -Rv ug+rw data/
, to ensure read/write permissions for the data dir & sqlite db file for user & group.
Test Server
-
php -S localhost:3000 server.php
to run a php test server - Go to http://localhost:3000 in your browser. use
admin
andadmin
for username and password - You should see "Nodes" and "Properties" headers.
- Click
calendars
->admin
-> scroll down toCreate New Calendar
form. - Put
taeluf
as the uri, andTaeluf's Calendar
as the Display Name (except use YOUR name!) - Click on the newly created calender under the
nodes
. Now copy this url, something likehttp://localhost:3000/calendars/admin/taeluf/
- In your email client or calendar program, use
http://localhost:3000/calendars/admin/taeluf/
as the url.- It may be
http://localhost:3000/principals/admin/
or justhttp://localhost:3000
depending on your client. see Sabre's CalDav page
- It may be
- Add a new event, and save it, to make sure it works! For extra testing, delete and re-add the server (to see if your added events re-download)
Dreamhost Shared Hosting Server
Now that the Php stuff is all working, let's set up an .htaccess
for DreamHost's
apache server.
Create a .htaccess
file & put this in it:
DirectoryIndex /server.php
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/server.php$
RewriteRule .* server.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
Now, ensure "Extra Web Security" is disabled on DreamHost for your dav domain.
Then, upload your files to your DH server!
Repeat the setup steps from Test Server
, but use dav.yourdomain.com
instead of localhost:3000
Finishing Setup | Users
Delete the admin user & create a new user. See the "Authentication" link above and inspect the sqlite database for more info.
Delete the admin user:
-
sqlite3 data/db.sqlite
-
delete * from users; delete * from principals;
Add a new user:
The simplest way is to use this php script I wrote. It modifies the users
table and principals
table
- Copy it into
bin/add-user.php
-
chmod ug+x bin/add-user.php
-
bin/add-user.php
, and answer the prompts. - Navigate to your dav domain in the browser & add a new calendar
Afterword, your CalDav url will be like: https://dav.yourdomain.com/calendars/user-name/calendar-name/
#!/usr/bin/env php
<?php
/**
* First, chmod ug+x bin/add-user.php
* @usage `bin/add-user.php`, then answer the prompts
*/
$db = __DIR__.'/../data/db.sqlite';
$pdo = new \PDO('sqlite:'.$db);
echo "\n# Add user\n\n";
$un = readline("Username: ");
$display_name = readline("Display Name: ");
// See https://www.php.net/manual/en/function.readline.php
// for a more robust readline solution that will not display your password as you type it
$pw = readline("Password: ");
readline_clear_history();
$email = readline("Email: ");
$pass_hash = md5($un.':SabreDav:'.$pw);
$sql = <<<SQL
INSERT INTO users (username, digesta1)
VALUES ('$un', '$pass_hash')
SQL;
// echo $sql;
$pdo->exec($sql);
$sql = <<<SQL
INSERT INTO principals (uri, email, displayname)
VALUES ('principals/$un','$email', '$display_name');
INSERT INTO principals (uri)
VALUES ('principals/$un/calendar-proxy-read'),
('principals/$un/calendar-proxy-write');
SQL;
$pdo->exec($sql);
Conclusion
CalDav is used to synchronize calendars between different devices and different people. DreamHost does not natively support CalDav with their Apache server, but they do allow you to run pretty much whatever software you want, even on shared hosting.
There is a free and open source PHP package called SabreDav which lets you run a CalDav server from a single PHP script (and of course all the dependencies that install through composer). SabreDav seems to do a LOT more than CalDav, but that's outside the scope of this post.
The best long-term solution would be for DreamHost to just add CalDav support. They already have WebDav, so I don't understand why they don't just add it. Tweet @DreamHost, contact them on their site, or otherwise nag them to add official CalDav support to their hosting plan.
I personally prefer to use self-hosted software over that which Big Tech offers. It just ... feels good. Also, it seems really silly that CalDav isn't more wide-spread. This stuff should NOT be so difficult.
It should be easy for an average computer user to setup their own CalDav server for extremely cheap, but this does not seem to be the case. Then again, I didn't shop around.
Errors you might have encountered
ModSecurity doesn't like the content type text/calendar
[Mon Feb 28 15:57:56.532405 2022] [:error] [pid 363916:tid 3573857371904] [client 111.222.333.44:58000] [client 111.222.333.44] ModSecurity: Warning. Match of "within %{tx.allowed_request_content_type}" against "TX:content_type" required. [file "/dh/apache2/template/etc/mod_sec3_CRS/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "956"] [id "920420"] [msg "Request content type is not allowed by policy"] [data "|text/calendar|"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153"] [tag "PCI/12.1"] [hostname "dav.yourwebsite.com"] [uri "/calendars/admin/taeluf/d10b67106646bb65ff458b0e74d70565d561ae42.ics"] [unique_id "0oD*5eO@2fK_5mO(5lG-0hX-6y"]
ModSecurity doesn't like highly escaped newlines
[Mon Feb 28 15:57:56.533750 2022] [:error] [pid 363916:tid 3573857371904] [client 111.222.333.44:58000] [client 111.222.333.44] ModSecurity: Warning. Pattern match "[\\n\\r]" at ARGS_NAMES:BEGIN:VCALENDAR\r\nCALSCALE:GREGORIAN\r\nPRODID:-//Ximian//NONSGML Evolution Calendar//EN\r\nVERSION:2.0\r\nBEGIN:VTIMEZONE\r\nTZID:America/Chicago\r\nX-LIC-LOCATION:America/Chicago\r\nBEGIN:DAYLIGHT\r\nTZNAME:CDT\r\nTZOFFSETFROM:-0600\r\nTZOFFSETTO:-0500\r\nDTSTART:20070311T020000\r\nRRULE:FREQ. [file "/dh/apache2/template/etc/mod_sec3_CRS/REQUEST-921-PROTOCOL-ATTACK.conf"] [line "171"] [id "921150"] [msg "HTTP Header Injection Attack via payload (CR/LF detected)"] [data "Matched Data: \x0d found within ARGS_NAMES:BEGIN:VCALENDAR\x5cr\x5cnCALSCALE:GREGORIAN\x5cr\x5cnPRODID:-//Ximian//NONSGML Evolution Calendar//EN\x5cr\x5cnVERSION:2.0\x5cr\x5cnBEGIN:VTIMEZONE\x5cr\x5cnTZID:America/Chicago\x5cr\x5cnX-LIC-LOCATION:America/Chicago\x5cr\x5cnBEGIN:DAYLIGHT\x5cr\x5cnTZNAME:CDT\x5cr\x5cnTZOFFSETFROM:-0600\x5cr\x5cnTZOFFSETTO:-0500\x5cr\x5cnDTSTART:20070311T020000\x5cr\x5cnRRULE:FREQ: BEGIN:VCALENDAR\x0d\x0aCALSCALE:GREGORIAN\x0d\x0aPRODID:-//Ximian//NONSGML Evolution [hostname "dav.yourwebsite.com"] [uri "/calendars/admin/taeluf/d10b67106646bb65ff458b0e74d70565d561ae42.ics"] [unique_id "0oD*5eO@2fK_5mO(5lG-0hX-6y"]
ModSecurity doesn't like a high anomaly score
[Mon Feb 28 15:57:56.538177 2022] [:error] [pid 363916:tid 3573857371904] [client 111.222.333.44:58000] [client 111.222.333.44] ModSecurity: Access denied with code 418 (phase 2). Operator GE matched 7 at TX:anomaly_score. [file "/dh/apache2/template/etc/mod_sec3_CRS/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "93"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "dav.yourwebsite.com"] [uri "/calendars/admin/taeluf/d10b67106646bb65ff458b0e74d70565d561ae42.ics"] [unique_id "0oD*5eO@2fK_5mO(5lG-0hX-6y"]