.. | ||
configuration.nix | ||
flake.lock | ||
flake.nix | ||
hardware-configuration.nix | ||
keys.txt | ||
README.md | ||
secrets.yaml | ||
sops.yaml | ||
ssh_config | ||
sshkey | ||
sshkey.pub |
Home Assistant Demo
This whole demo is highly insecure as all the private keys are available publicly. This is only done for convenience as it is just a demo. Do not expose the VM to the internet.
The flake.nix
file sets up a Home Assistant server in only about 15
lines of related code. It also defines a Home Assistant server that integrates with
a LDAP server.
This guide will show how to deploy this setup to a Virtual Machine, like showed here, in 4 commands.
Deploy to the VM
Build the VM and start it:
rm nixos.qcow2; \
nixos-rebuild build-vm-with-bootloader --fast -I nixos-config=./configuration.nix -I nixpkgs=. ; \
QEMU_NET_OPTS="hostfwd=tcp::2222-:2222,hostfwd=tcp::8080-:80" ./result/bin/run-nixos-vm
This last call is blocking, so I advice adding a &
at the end of the command otherwise you will
need to run the rest of the commands in another terminal.
With the VM started, make the secrets in secrets.yaml
decryptable in the VM. This change will
appear in git status
but you don't need to commit this.
SOPS_AGE_KEY_FILE=keys.txt \
nix run --impure nixpkgs#sops -- --config sops.yaml -r -i \
--add-age $(nix shell nixpkgs#ssh-to-age --command sh -c 'ssh-keyscan -p 2222 -t ed25519 -4 localhost 2>/dev/null | ssh-to-age') \
secrets.yaml
The nested command, the one in between the parenthesis $(...)
, is used to print the VM's public
age key, which is then added to the secrets.yaml
file in order to make the secrets decryptable by
the VM.
If you forget this step, the deploy will seem to go fine but the secrets won't be populated and neither LLDAP nor Home Assistant will start.
Make the ssh key private:
chmod 600 sshkey
This is only needed because git mangles with the permissions. You will not even see this change in
git status
.
You can ssh into the VM with, but this is not required for the demo:
ssh -F ssh_config example
Finally, we can deploy. To deploy a Home Assistant server, run:
SSH_CONFIG_FILE=ssh_config nix run nixpkgs#colmena --impure -- apply --on basic
To deploy a Home Assistant server integrated with a LDAP service, run:
SSH_CONFIG_FILE=ssh_config nix run nixpkgs#colmena --impure -- apply --on ldap
The deploy will take a few minutes the first time and subsequent deploys will take around 15 seconds.
Access Home Assistant Through Your Browser
Add the following entry to your /etc/hosts
file:
networking.hosts = {
"127.0.0.1" = [ "ha.example.com" ];
};
Which produces:
$ cat /etc/hosts
127.0.0.1 ha.example.com
If you deployed the ldap
target host, add instead:
networking.hosts = {
"127.0.0.1" = [ "ha.example.com" "ldap.example.com" ];
};
If you deployed the basic
target host, go to
http://ha.example.com:8080 and you will be greeted with the Home
Assistant setup wizard which will allow you to create an admin user:
And that's the end of the demo. Otherwise if you deployed the ldap
target host, go first to
http://ldap.example.com:8080 and login with:
- username:
admin
- password: the value of the field
lldap.user_password
in thesecrets.yaml
file which isfccb94f0f64bddfe299c81410096499a
.
Create the group homeassistant_user
and a user assigned to that group.
Go to http://ha.example.com:8080 and login with the user and password you just created above.
In More Details
Files
flake.nix
: nix entry point, defines one target host for colmena to deploy to as well as the selfhostblock's config for setting up the home assistant server paired with the LDAP server.configuration.nix
: defines all configuration required for colmena to deploy to the VM. The file has comments if you're interested.hardware-configuration.nix
: defines VM specific layout. This was generated with nixos-generate-config on the VM.- Secrets related files:
keys.txt
: your private key for sops-nix, allows you to edit thesecrets.yaml
file. This file should never be published but here I did it for convenience, to be able to deploy to the VM in less steps.secrets.yaml
: encrypted file containing required secrets for Home Assistant and the LDAP server. This file can be publicly accessible.sops.yaml
: describes how to create thesecrets.yaml
file. Can be publicly accessible.
- SSH related files:
sshkey(.pub)
: your private and public ssh keys. Again, the private key should usually not be published as it is here but this makes it possible to deploy to the VM in less steps.ssh_config
: the ssh config allowing you to ssh into the VM by just using the hostnameexample
. Usually you would store this info in your~/.ssh/config
file but it's provided here to avoid making you do that.
Virtual Machine
More info about the VM.
We use build-vm-with-bootloader
instead of just build-vm
as that's the only way to deploy to the VM.
The VM's User and password are both nixos
, as setup in the configuration.nix
file under
user.users.nixos.initialPassword
.
You can login with ssh -F ssh_config example
. You just need to accept the fingerprint.
The VM's hard drive is a file name nixos.qcow2
in this directory. It is created when you first create the VM and re-used since. You can just remove it when you're done.
That being said, the VM uses tmpfs
to create the writable nix store so if you stumble in a disk
space issue, you must increase the
virtualisation.vmVariantWithBootLoader.virtualisation.memorySize
setting.
Secrets
More info about the secrets.
The private key in the keys.txt
file is created with:
$ nix shell nixpkgs#age --command age-keygen -o keys.txt
Public key: age1algdv9xwjre3tm7969eyremfw2ftx4h8qehmmjzksrv7f2qve9dqg8pug7
We use the printed public key in the admin
field of the sops.yaml
file.
To open the secrets.yaml
file and optionnally edit it, run:
SOPS_AGE_KEY_FILE=keys.txt nix run --impure nixpkgs#sops -- \
--config sops.yaml \
secrets.yaml
The secrets.yaml
file must follow the format:
home-assistant: |
name: "My Instance"
country: "US"
latitude_home: "0.100"
longitude_home: "-0.100"
time_zone: "America/Los_Angeles"
unit_system: "metric"
lldap:
user_password: XXX...
jwt_secret: YYY...
Important: the value of the
home-assistant
field is a string that looks like yaml. Do not remove the pipe (|) sign.
You can generate random secrets with:
$ nix run nixpkgs#openssl -- rand -hex 64
If you choose a password too small, ldap could refuse to start.
Why do we need the VM's public key
The sops.yaml
file describes what private keys can decrypt and encrypt the
secrets.yaml
file containing the application secrets. Usually, you will create and add
secrets to that file and when deploying, it will be decrypted and the secrets will be copied
in the /run/secrets
folder on the VM. We thus need one private key for you to edit the
secrets.yaml
file and one in the VM for it to decrypt the secrets.
Your private key is already pre-generated in this repo, it's the sshkey
file. But when
creating the VM in the step above, a new private key and its accompanying public key were
automatically generated under /etc/ssh/ssh_host_ed25519_key
in the VM. We just need to get the
public key and add it to the secrets.yaml
which we did in the Deploy section.
SSH
The private and public ssh keys were created with:
ssh-keygen -t ed25519 -f sshkey
You don't need to copy over the ssh public key over to the VM as we set the keyFiles
option which copies the public key when the VM gets created.
This allows us also to disable ssh password authentication.
For reference, if instead you didn't copy the key over on VM creating and enabled ssh authentication, here is what you would need to do to copy over the key:
nix shell nixpkgs#openssh --command ssh-copy-id -i sshkey -F ssh_config example
Deploy
If you get a NAR hash mismatch error like hereunder, you need to run nix flake lock --update-input selfhostblocks
.
error: NAR hash mismatch in input ...
Update Demo
If you update the Self Host Blocks configuration in flake.nix
file, you can just re-deploy.
If you update the configuration.nix
file, you will need to rebuild the VM from scratch.
If you update a module in the Self Host Blocks repository, you will need to update the lock file with:
nix flake lock --override-input selfhostblocks ../.. --update-input selfhostblocks