├── .github └── workflows │ └── deploy.yml ├── flake.nix ├── README.md └── flake.lock /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build & Deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | env: 10 | CACHE_NAME: mycustomcache 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - run: sudo rm -rf /opt& 16 | - uses: actions/checkout@v3 17 | - uses: cachix/install-nix-action@v18 18 | - uses: cachix/cachix-action@v12 19 | with: 20 | name: "${{ env.CACHE_NAME }}" 21 | authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" 22 | - name: Build 23 | run: nix build -L 24 | - name: Deploy 25 | if: github.ref == 'refs/heads/main' 26 | env: 27 | CACHIX_ACTIVATE_TOKEN: "${{ secrets.CACHIX_ACTIVATE_TOKEN }}" 28 | run: | 29 | cachix push $CACHE_NAME ./result 30 | # --agent is needed due to a regression in Cachix 1.1, which will be fixed in Cachix 1.2 31 | cachix deploy activate --agent myagent ./result 32 | 33 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = ""; 3 | 4 | inputs = { 5 | cachix-deploy-flake.url = "github:cachix/cachix-deploy-flake"; 6 | }; 7 | 8 | outputs = { nixpkgs, cachix-deploy-flake, ... }: 9 | let 10 | # change these 11 | machineName = "myagent"; 12 | sshPubKey = "ssh-rsa XXX me@machine"; 13 | 14 | lib = nixpkgs.lib; 15 | forAllSystems = lib.genAttrs lib.systems.flakeExposed; 16 | common = system: rec { 17 | pkgs = nixpkgs.legacyPackages.${system}; 18 | cachix-deploy-lib = cachix-deploy-flake.lib pkgs; 19 | bootstrapNixOS = cachix-deploy-lib.bootstrapNixOS { 20 | system = system; 21 | hostname = machineName; 22 | grubDevices = [ "/dev/nvme0n1" "/dev/nvme1n1" ]; 23 | sshPubKey = sshPubKey; 24 | }; 25 | }; 26 | in { 27 | nixosConfigurations.${machineName} = (common "x86_64-linux").bootstrapNixOS.nixos; 28 | 29 | packages = forAllSystems (system: 30 | let 31 | inherit (common system) pkgs cachix-deploy-lib bootstrapNixOS; 32 | in { 33 | default = cachix-deploy-lib.spec { 34 | agents = { 35 | "${machineName}" = cachix-deploy-lib.nixos { 36 | imports = [ bootstrapNixOS.module ]; 37 | 38 | config = { 39 | # here comes all your NixOS configuration 40 | }; 41 | }; 42 | }; 43 | }; 44 | }); 45 | 46 | devShells = forAllSystems (system: 47 | let 48 | inherit (common system) pkgs; 49 | in { 50 | default = pkgs.mkShell { 51 | buildInputs = [ 52 | cachix-deploy-flake.packages.${system}.bootstrapHetzner 53 | ]; 54 | }; 55 | }); 56 | }; 57 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Hetzner Dedicated 2 | 3 | Usually used for a beefy building machine or CI, [Hetzner offers](https://www.hetzner.com/dedicated-rootserver/matrix-ax) 4 | the best price/performance. 5 | 6 | Since these machines are bare metal, setting them up comes up with a cost - no more! 7 | 8 | This setup uses a single command to bootstrap a machine and was tested using 9 | [AX51-NVMe](https://www.hetzner.com/dedicated-rootserver/ax51-nvme), 10 | but any machine with two SSDs should work. 11 | 12 | Please contact [domen@cachix.org](mailto:domen@cachix.org) if you're having a different machine configuration or need support. 13 | 14 | It will set up a machine using raid1 and ext4 for the root filesystem. 15 | 16 | ## Rebooting the machine into rescue mode 17 | 18 | 1. Login to [Hetzner Robot](https://robot.hetzner.com/server) 19 | 2. Make sure to put your SSH key into https://robot.hetzner.com/key/index 20 | 3. Select the server you'd like to deploy 21 | 4. Click `Rescue` -> Make sure you have `linux` selected and your SSH key -> Click `Activate` 22 | 5. Click `Reset` -> Select `Execute an automatic hardware reset` -> Click `Send` 23 | 24 | ## Setting up Cachix 25 | 26 | 1. Open [Cachix](https://app.cachix.org/) 27 | 2. If you're part of a team, click `Select an account` and click `Create an organization`. 28 | 3. Click `Caches` in the top of the menu and create a new binary cache. 29 | 1. Open [Cachix Deploy](https://app.cachix.org/deploy) 30 | 2. Select the account/organization in the menu 31 | 3. Create a new workspace by selecting the previously created binary cache. 32 | 4. Click "Add an agent" 33 | 5. Pick a description and generate a token 34 | 6. Save the token as `CACHIX_AGENT_TOKEN=xxx` to `cachix-agent.token` 35 | 36 | ## Bootstrapping the machine 37 | 38 | Clone this repo and make sure to set `sshPubKey` in `flake.nix` with your public SSH key. 39 | 40 | From the email you received when the Hetzner machine was processed, take IP and replace it in `yourip`: 41 | 42 | ```shell-session 43 | $ nix develop -c bootstrap-hetzner yourip myagent ./cachix-agent.token 44 | ``` 45 | 46 | Once the script finishes, your machine should come up in a few minutes and show up in your Cachix Deploy workspace. 47 | 48 | In case anything goes wrong, you can order a remote console via the `Support` tab in [Hetzner Robot](https://robot.hetzner.com/server). 49 | 50 | ## Using Actions for CD 51 | 52 | Your machine is running a plain NixOS configuration. 53 | 54 | To deploy any changes from `main` branch you'll need to configure a few things in `.github/workflows/deploy.yml`: 55 | 56 | - `myagent`: if you picked a different agent/hostname, change it here 57 | - `CACHE_NAME`: change `mycustomcache` into the name of the cache you created. 58 | - `CACHIX_AUTH_TOKEN`: in [Cachix](https://app.cachix.org/), find your cache via settings and create a write auth token. Go to your git repository, click `Settings`, click `Secrets`, click `Actions` and add it as a repository setting. 59 | - `CACHIX_ACTIVATE_TOKEN` in [Cachix Deploy](https://app.cachix.org/deploy), click on your newly created workspace and click "Start a deployment" to generate an token. Go to your git repository, click `Settings`, click `Secrets`, click `Actions` and add it as a repository setting. 60 | 61 | ## Setting up self-hosted GitHub runners 62 | 63 | Assuming your github organization is called `myorg`, here's the NixOS configuration: 64 | 65 | ``` 66 | nix.trustedUsers = [ "root" "github-runner-myorg" ]; 67 | 68 | systemd.services.github-runner-myorg.serviceConfig.ReadWritePaths = [ "/nix/var/nix/profiles/per-user/" ]; 69 | 70 | services.github-runners.myorg = { 71 | enable = true; 72 | url = "https://github.com/myorg"; 73 | tokenFile = "/etc/secrets/github-runner/myorg.token"; 74 | extraPackages = [ pkgs.cachix ]; 75 | }; 76 | ``` 77 | 78 | And then go to (make sure to replace myorg with the organization's name) https://github.com/organizations/myorg/settings/actions/runners and copy the token to `/etc/secrets/github-runner/myorg.token`. 79 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "cachix-deploy-flake": { 4 | "inputs": { 5 | "darwin": "darwin", 6 | "disko": "disko", 7 | "home-manager": "home-manager", 8 | "nixos-remote": "nixos-remote", 9 | "nixpkgs": "nixpkgs_2" 10 | }, 11 | "locked": { 12 | "lastModified": 1672314203, 13 | "narHash": "sha256-pP/1pjq9A7TIlOjHOTj73VdU6bAPqm3ofdJbK1L51k8=", 14 | "owner": "cachix", 15 | "repo": "cachix-deploy-flake", 16 | "rev": "b5086071c34900fe5ab17090bf9a9b4c320de287", 17 | "type": "github" 18 | }, 19 | "original": { 20 | "owner": "cachix", 21 | "repo": "cachix-deploy-flake", 22 | "type": "github" 23 | } 24 | }, 25 | "darwin": { 26 | "inputs": { 27 | "nixpkgs": "nixpkgs" 28 | }, 29 | "locked": { 30 | "lastModified": 1657835815, 31 | "narHash": "sha256-CnZszAYpNKydh6N7+xg+eRtWNVoAAGqc6bg+Lpgq1xc=", 32 | "owner": "LnL7", 33 | "repo": "nix-darwin", 34 | "rev": "54a24f042f93c79f5679f133faddedec61955cf2", 35 | "type": "github" 36 | }, 37 | "original": { 38 | "owner": "LnL7", 39 | "repo": "nix-darwin", 40 | "type": "github" 41 | } 42 | }, 43 | "disko": { 44 | "inputs": { 45 | "nixpkgs": [ 46 | "cachix-deploy-flake", 47 | "nixpkgs" 48 | ] 49 | }, 50 | "locked": { 51 | "lastModified": 1672163301, 52 | "narHash": "sha256-ClIIPeY0SyZjlc9b1+EorH5DiCyYBSsUOOu9dXEwrXE=", 53 | "owner": "nix-community", 54 | "repo": "disko", 55 | "rev": "df3a607ad7ee431f4831a51af2c464aa8a8813f4", 56 | "type": "github" 57 | }, 58 | "original": { 59 | "owner": "nix-community", 60 | "repo": "disko", 61 | "type": "github" 62 | } 63 | }, 64 | "home-manager": { 65 | "inputs": { 66 | "nixpkgs": [ 67 | "cachix-deploy-flake", 68 | "nixpkgs" 69 | ], 70 | "utils": "utils" 71 | }, 72 | "locked": { 73 | "lastModified": 1671958483, 74 | "narHash": "sha256-wX+VBdHwrpW654PzmM4efiPdUDI8da8TGZeQt/zYP40=", 75 | "owner": "nix-community", 76 | "repo": "home-manager", 77 | "rev": "939731b8cb75fb451170cb8f935186a6a7424444", 78 | "type": "github" 79 | }, 80 | "original": { 81 | "owner": "nix-community", 82 | "repo": "home-manager", 83 | "type": "github" 84 | } 85 | }, 86 | "nixos-2211": { 87 | "locked": { 88 | "lastModified": 1659446231, 89 | "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", 90 | "owner": "NixOS", 91 | "repo": "nixpkgs", 92 | "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", 93 | "type": "github" 94 | }, 95 | "original": { 96 | "owner": "NixOS", 97 | "ref": "release-21.11", 98 | "repo": "nixpkgs", 99 | "type": "github" 100 | } 101 | }, 102 | "nixos-images": { 103 | "inputs": { 104 | "nixos-2211": "nixos-2211", 105 | "nixos-unstable": "nixos-unstable" 106 | }, 107 | "locked": { 108 | "lastModified": 1671788592, 109 | "narHash": "sha256-MFcGltfuAicQ5FUHYiBzRjy4YMmEOcbFSVEY1bK1Oho=", 110 | "owner": "nix-community", 111 | "repo": "nixos-images", 112 | "rev": "b14097667f2a9889083d6401ba468b046b2b52f1", 113 | "type": "github" 114 | }, 115 | "original": { 116 | "owner": "nix-community", 117 | "repo": "nixos-images", 118 | "type": "github" 119 | } 120 | }, 121 | "nixos-remote": { 122 | "inputs": { 123 | "disko": [ 124 | "cachix-deploy-flake", 125 | "disko" 126 | ], 127 | "nixos-images": "nixos-images", 128 | "nixpkgs": [ 129 | "cachix-deploy-flake", 130 | "nixpkgs" 131 | ] 132 | }, 133 | "locked": { 134 | "lastModified": 1672166621, 135 | "narHash": "sha256-ctOgYA4Q5zsnZTRa4pj9tAPU2xACi/A3RRBebtWjhWc=", 136 | "owner": "numtide", 137 | "repo": "nixos-remote", 138 | "rev": "8ed88da3696f50f1ffe4ebd29e186a0cd672533c", 139 | "type": "github" 140 | }, 141 | "original": { 142 | "owner": "numtide", 143 | "repo": "nixos-remote", 144 | "type": "github" 145 | } 146 | }, 147 | "nixos-unstable": { 148 | "locked": { 149 | "lastModified": 1671565324, 150 | "narHash": "sha256-FKnxM+07rV3HFNIOw3p1XaopZ3MkaxuHXNcZyYUJt2w=", 151 | "owner": "NixOS", 152 | "repo": "nixpkgs", 153 | "rev": "3c6d63d22ca8b57adc4120f7c1ea5262925c8c2d", 154 | "type": "github" 155 | }, 156 | "original": { 157 | "owner": "NixOS", 158 | "ref": "nixos-unstable-small", 159 | "repo": "nixpkgs", 160 | "type": "github" 161 | } 162 | }, 163 | "nixpkgs": { 164 | "locked": { 165 | "lastModified": 1602411953, 166 | "narHash": "sha256-gbupmxRpoQZqL5NBQCJN2GI5G7XDEHHHYKhVwEj5+Ps=", 167 | "owner": "LnL7", 168 | "repo": "nixpkgs", 169 | "rev": "f780534ea2d0c12e62607ff254b6b45f46653f7a", 170 | "type": "github" 171 | }, 172 | "original": { 173 | "id": "nixpkgs", 174 | "type": "indirect" 175 | } 176 | }, 177 | "nixpkgs_2": { 178 | "locked": { 179 | "lastModified": 1672249180, 180 | "narHash": "sha256-ipos/gTMHqxS39asqNWEJZ7nXdcTHa0TB0AIZXkGapg=", 181 | "owner": "NixOS", 182 | "repo": "nixpkgs", 183 | "rev": "e58a7747db96c23b8a977e7c1bbfc5753b81b6fa", 184 | "type": "github" 185 | }, 186 | "original": { 187 | "id": "nixpkgs", 188 | "type": "indirect" 189 | } 190 | }, 191 | "nixpkgs_3": { 192 | "locked": { 193 | "lastModified": 1672249180, 194 | "narHash": "sha256-ipos/gTMHqxS39asqNWEJZ7nXdcTHa0TB0AIZXkGapg=", 195 | "owner": "NixOS", 196 | "repo": "nixpkgs", 197 | "rev": "e58a7747db96c23b8a977e7c1bbfc5753b81b6fa", 198 | "type": "github" 199 | }, 200 | "original": { 201 | "id": "nixpkgs", 202 | "type": "indirect" 203 | } 204 | }, 205 | "root": { 206 | "inputs": { 207 | "cachix-deploy-flake": "cachix-deploy-flake", 208 | "nixpkgs": "nixpkgs_3" 209 | } 210 | }, 211 | "utils": { 212 | "locked": { 213 | "lastModified": 1667395993, 214 | "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", 215 | "owner": "numtide", 216 | "repo": "flake-utils", 217 | "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", 218 | "type": "github" 219 | }, 220 | "original": { 221 | "owner": "numtide", 222 | "repo": "flake-utils", 223 | "type": "github" 224 | } 225 | } 226 | }, 227 | "root": "root", 228 | "version": 7 229 | } 230 | --------------------------------------------------------------------------------