Alex Payne 5f192bd5bb Merge pull request #372 from neuhaus/patch-1 | 9年前 | |
---|---|---|
roles | 9年前 | |
vars | 9年前 | |
.gitignore | 11年前 | |
.travis.yml | 11年前 | |
README.md | 9年前 | |
Vagrantfile | 10年前 | |
hosts | 11年前 | |
requirements.txt | 10年前 | |
site.yml | 10年前 | |
tests.py | 10年前 |
Sovereign is a set of Ansible playbooks that you can use to build and maintain your own personal cloud (I know I know). It’s based entirely on open source software, so you’re in control.
If you’ve never used Ansible before, you a) are in for a treat and b) might find these playbooks useful to learn from, since they show off a fair bit of what the tool can do.
I had been a paying Google Apps customer for personal and corporate use since the service was in beta. Until several weeks ago, that is. I was about to set up another Google Apps account for a new project when I stopped to consider what I would be funding with my USD \$50 per user per year:
To each her/his own, but personally I saw little reason to continue participating in the Google ecosystem. It had been years since I last ran my own server for email and such, but it’s only gotten cheaper and easier to do so. Plus, none of the commercial alternatives I looked at provided all the services I was looking for.
Rather than writing up a long and hard-to-follow set of instructions, I decided to share my server setup in a format that you can more or less just clone, configure, and run. Ansible seemed like the most appropriate way to do that: it’s simple, straightforward, and easy to pick up.
I’ve been using this setup for about a month now and it’s been great. It’s also replaced some non-Google services I used, saving me money and making me feel like I’ve got a little more privacy.
A big chunk of the initial version was inspired by this post by Drew Crawford. Unlike Drew, my goal is not “NSA-proofing” email, just providing a reasonable alternative to Google Apps that isn’t wildly insecure. If you need serious privacy and security (ex: for dissident activities), Sovereign might be useful as a starting point but will require additional work. Be careful out there.
What do you get if you point this thing at a VPS? All kinds of good stuff!
No setup is perfect, but the general idea is to provide a bunch of useful services while being reasonably secure and low-maintenance. Set it up, SSH in every couple weeks, but mostly forget about it.
Don’t want one or more of the above services? Comment out the relevant role in site.yml
. Or get more granular and comment out the associated include:
directive in one of the playbooks.
Generate a private key and a certificate signing request (CSR):
openssl req -nodes -newkey rsa:2048 -keyout roles/common/files/wildcard_private.key -out mycert.csr
Purchase a wildcard cert from a certificate authority, such as Positive SSL or AlphaSSL. You will provide them with the contents of your CSR, and in return they will give you your signed public certificate. Place the certificate in roles/common/files/wildcard_public_cert.crt
.
Download your certificate authority’s combined cert to roles/common/files/wildcard_ca.pem
. You can also download the intermediate and root certificates separately and concatenate them together in that order.
Lastly, test your certificate:
openssl verify -verbose -CAfile roles/common/files/wildcard_ca.pem roles/common/files/wildcard_public_cert.crt
Purchasing SSL certs, and wildcard certs specifically, can be a significant financial burden. It is possible to generate a self-signed SSL certificate (i.e. one that isn’t signed by a Certificate Authority) that is free of charge by nature. However, since a self-signed cert has no CA chain that can confirm its authenticity, some services might behave erratically when using such a certificate.
To create a self-signed SSL cert, run the following commands:
openssl req -nodes -newkey rsa:2048 -keyout roles/common/files/wildcard_private.key -out mycert.csr
openssl x509 -req -days 365 -in mycert.csr -signkey roles/common/files/wildcard_private.key -out roles/common/files/wildcard_public_cert.crt
cp roles/common/files/wildcard_public_cert.crt roles/common/files/wildcard_ca.pem
If you haven’t already, download and install Tarsnap, or use brew install tarsnap
if you use Homebrew.
Create a new machine key for your server:
tarsnap-keygen --keyfile roles/tarsnap/files/decrypted_tarsnap.key --user me@example.com --machine example.com
For goodness sake, change the root password:
passwd
Create a user account for Ansible to do its thing through:
useradd deploy
passwd deploy
mkdir /home/deploy
Authorize your ssh key if you want passwordless ssh login (optional):
mkdir /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys
chmod 400 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy -R
echo 'deploy ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/deploy
Your new account will be automatically set up for passwordless sudo
.
Modify the settings in vars/user.yml
to your liking. If you want to see how they’re used in context, just search for the corresponding string.
Setting password_hash
for your mail users is a bit tricky. You can generate one using doveadm-pw.
# doveadm pw -s SHA512-CRYPT
Enter new password: foo
Retype new password: foo
{SHA512-CRYPT}$6$drlIN9fx7Aj7/iLu$XvjeuQh5tlzNpNfs4NwxN7.HGRLglTKism0hxs2C1OvD02d3x8OBN9KQTueTr53nTJwVShtCYiW80SGXAjSyM0
Remove {SHA512-CRYPT}
and insert the rest as the password_hash
value.
Alternatively, if you don’t already have doveadm
installed, Python 3.3 or higher on Linux will generate the appropriate string for you (assuming your password is password
):
python3 -c 'import crypt; print(crypt.crypt("password", salt=crypt.METHOD_SHA512))'
On OS X and other platforms the passlib package may be used to generate the required string:
python -c 'import passlib.hash; print(passlib.hash.sha512_crypt.encrypt("password", rounds=5000))'
Same for the IRC password hash…
# znc --makepass
[ ** ] Type your new password.
[ ?? ] Enter Password: foo
[ ?? ] Confirm Password: foo
[ ** ] Kill ZNC process, if it's running.
[ ** ] Then replace password in the <User> section of your config with this:
<Pass password>
Method = sha256
Hash = 310c5f99825e80d5b1d663a0a993b8701255f16b2f6056f335ba6e3e720e57ed
Salt = YdlPM5yjBmc/;JO6cfL5
</Pass>
[ ** ] After that start ZNC again, and you should be able to login with the new password.
Take the strings after Hash =
and Salt =
and insert them as the value for irc_password_hash
and irc_password_salt
respectively.
Alternatively, if you don’t already have znc
installed, Python 3.3 or higher on Linux will generate the appropriate string for you (assuming your password is password
):
python3 -c 'import crypt; print("irc_password_salt: {}\nirc_password_hash: {}".format(*crypt.crypt("password", salt=crypt.METHOD_SHA256).split("$")[2:]))'
On OS X and other platforms the passlib:https://pythonhosted.org/passlib/ package may be used to generate the required string:
python -c 'import passlib.hash; print("irc_password_salt: {}\nirc_password_hash: {}".format(*passlib.hash.sha256_crypt.encrypt("password", rounds=5000).split("$")[2:]))'
For Git hosting, copy your public key into place:
cp ~/.ssh/id_rsa.pub roles/git/files/gitolite.pub
Finally, replace the TODOs in the file hosts
. If your SSH daemon listens on a non-standard port, add a colon and the port number after the IP address. In that case you also need to add your custom port to the task Set firewall rules for web traffic and SSH
in the file roles/common/tasks/ufw.yml
.
First, make sure you’ve got Ansible 1.6+ installed.
To run the whole dang thing:
ansible-playbook -i ./hosts site.yml
To run just one or more piece, use tags. I try to tag all my includes for easy isolated development. For example, to focus in on your firewall setup:
ansible-playbook -i ./hosts --tags=ufw site.yml
You might find that it fails at one point or another. This is probably because something needs to be done manually, usually because there’s no good way of automating it. Fortunately, all the tasks are clearly named so you should be able to find out where it stopped. I’ve tried to add comments where manual intervention is necessary.
If you’ve just bought a new domain name, point it at Linode’s DNS Manager or similar. Most VPS services (and even some domain registrars) offer a managed DNS service that you can use for this at no charge. If you’re using an existing domain that’s already managed elsewhere, you can probably just modify a few records.
Create A
records which point to your server’s IP address:
example.com
mail.example.com
autoconfig.example.com
(for email client automatic configuration)read.example.com
(for Wallabag)news.example.com
(for Selfoss)cloud.example.com
(for ownCloud)git.example.com
(for cgit)Create a MX
record for example.com
which assigns mail.example.com
as the domain’s mail server.
To ensure your emails pass DKIM checks you need to add a txt
record. The name field will be default._domainkey.EXAMPLE.COM.
The value field contains the public key used by OpenDKIM. The exact value needed can be found in the file /etc/opendkim/keys/EXAMPLE.COM/default.txt
it’ll look something like this:
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKKAQfMwKVx+oJripQI+Ag4uTwYnsXKjgBGtl7Tk6UMTUwhMqnitqbR/ZQEZjcNolTkNDtyKZY2Z6LqvM4KsrITpiMbkV1eX6GKczT8Lws5KXn+6BHCKULGdireTAUr3Id7mtjLrbi/E3248Pq0Zs39hkDxsDcve12WccjafJVwIDAQAB
Set up SPF and reverse DNS as per this post. Make sure to validate that it’s all working, for example by sending an email to check-auth@verifier.port25.com and reviewing the report that will be emailed back to you.
Sign in to the ZNC web interface and set things up to your liking. It isn’t exposed through the firewall, so you must first set up an SSH tunnel:
ssh deploy@example.com -L 6643:localhost:6643
Then proceed to http://localhost:6643 in your web browser.
Finally, sign into ownCloud to set it up. You should select PostgreSQL as the configuration backend.
We’re collecting known-good client setups on our wiki.
If you run into an errors, please check the wiki page. If the problem you encountered, is not listed, please go ahead and create an issue. If you already have a bugfix and/or workaround, just put them in the issue and the wiki page.
You will need to manually enter the password for any encrypted volumes on reboot. This is not Sovereign-specific, but rather a function of how EncFS works. This will necessitate SSHing into your machine after reboot, or accessing it via a console interface if one is available to you. Once you’re in, run this:
encfs /encrypted /decrypted --public
It is possible that some daemons may need to be restarted after you enter your password for the encrypted volume(s). Some services may stall out while looking for resources that will only be available once the /decrypted
volume is available and visible to daemon user accounts.
Ask questions and provide feedback in #sovereign
on Freenode.
You may want to set up a local development environment so that you don’t have to test on your real server.
If you improve one of the provided playbooks or add an exciting new one, send a pull request. Everyone benefits.
Original content is GPLv3, same as Ansible. All files and templates based on third-party software should be considered under their respective licenses.