|
| 1 | +--- |
| 2 | +title: "How To: OpenBSD (on a Remote Server)" |
| 3 | +dateCreated: 2025-12-12 |
| 4 | +dateUpdated: 2025-12-12 |
| 5 | +--- |
| 6 | + |
| 7 | +## Preamble |
| 8 | + |
| 9 | +### Aims |
| 10 | + |
| 11 | +To document the steps I recently took to set up an OpenBSD server, so I don't |
| 12 | +end up forgetting them. |
| 13 | + |
| 14 | +Since most of these steps are the same steps you'd take to set up any server but |
| 15 | +with commands specific to OpenBSD, the end result of following them should be a |
| 16 | +general purpose, relatively secure server that you can SSH into for subsequent |
| 17 | +configuration and activity. |
| 18 | + |
| 19 | +### Assumptions |
| 20 | + |
| 21 | +- Familiarity with Unix-like operating systems and SSH |
| 22 | +- Some understanding of networking |
| 23 | + |
| 24 | +### Caveats |
| 25 | + |
| 26 | +I'm pretty new to OpenBSD and system administration in general, so there may be |
| 27 | +errors in this document. You should consider this as a resource, not the be-all |
| 28 | +and end-all of all the steps you should take to set up an OpenBSD server. |
| 29 | + |
| 30 | +Additionally, this skips installation, disk partitioning, network setup, etc. |
| 31 | +since the server provider I use supports OpenBSD out of the box and already |
| 32 | +handles those things when spinning up new instances. If you need them, some of |
| 33 | +my references below discuss those steps. |
| 34 | + |
| 35 | +## Steps |
| 36 | + |
| 37 | +1. (Local) SSH as root: |
| 38 | + |
| 39 | + ```console |
| 40 | + ssh root@<ip> |
| 41 | + ``` |
| 42 | + |
| 43 | +2. (Remote as root) Change default root password: |
| 44 | + |
| 45 | + ```console |
| 46 | + passwd |
| 47 | + ``` |
| 48 | + |
| 49 | +3. (Local) SSH as root again to verify the new password works: |
| 50 | + |
| 51 | + ```console |
| 52 | + ssh root@<ip> |
| 53 | + ``` |
| 54 | + |
| 55 | + **Note:** To prevent losing access to your server, only exit your original |
| 56 | + root session once you've confirmed that the new password is reflected. |
| 57 | + |
| 58 | +4. (Remote as root) Update system: |
| 59 | + |
| 60 | + ```console |
| 61 | + syspatch |
| 62 | + ``` |
| 63 | + |
| 64 | + **Note:** Depending on what patches are applied, you may need to do |
| 65 | + additional steps such as restarting services or rebooting the server. |
| 66 | + |
| 67 | +5. (Remote as root) Update third-party software: |
| 68 | + |
| 69 | + ```console |
| 70 | + pkg_add -u |
| 71 | + ``` |
| 72 | + |
| 73 | + **Note:** This is unlikely to update anything as base OpenBSD doesn't have |
| 74 | + any third-party software, but it's just good practice to have the muscle |
| 75 | + memory of updating third-party software after the system. |
| 76 | + |
| 77 | +6. (Remote as root) Install third-party software: |
| 78 | + |
| 79 | + ```console |
| 80 | + pkg_add <package> |
| 81 | + ``` |
| 82 | + |
| 83 | + **Note:** This is optional and can be done at a later time. However, base |
| 84 | + OpenBSD primarily only has vi or Mg for text editing and netcat (`nc`) or |
| 85 | + `ftp` for making network requests. These tools can be unintuitive for users |
| 86 | + unfamiliar with them (like me), so you may want to install Vim or nano and |
| 87 | + cURL or Wget, respectively. |
| 88 | + |
| 89 | +7. (Remote as root) Give wheel group users admin access: |
| 90 | + |
| 91 | + ```console |
| 92 | + echo "permit persist :wheel" > /etc/doas.conf |
| 93 | + ``` |
| 94 | + |
| 95 | +8. (Remote as root) Create admin user: |
| 96 | + |
| 97 | + ```console |
| 98 | + useradd -m -G wheel <username> |
| 99 | + ``` |
| 100 | + |
| 101 | +9. (Remote as root) Set admin user password: |
| 102 | + |
| 103 | + ```console |
| 104 | + passwd <username> |
| 105 | + ``` |
| 106 | + |
| 107 | +10. (Local) Generate SSH key pair: |
| 108 | + |
| 109 | + ```console |
| 110 | + ssh-keygen -t ed25519 -C <comment> |
| 111 | + ``` |
| 112 | + |
| 113 | +11. (Remote as root) Add generated public key to |
| 114 | + `/home/<username>/.ssh/authorized_keys` |
| 115 | +12. (Remote as root) Harden SSH: |
| 116 | + |
| 117 | + ```console |
| 118 | + vi /etc/ssh/sshd_config |
| 119 | + ``` |
| 120 | + |
| 121 | + Then, update or add the following: |
| 122 | + |
| 123 | + ```text |
| 124 | + # Change default SSH port |
| 125 | + Port <port> |
| 126 | + |
| 127 | + # Only listen to specific IP |
| 128 | + AddressFamily <family> |
| 129 | + ListenAddress <ip> |
| 130 | + |
| 131 | + # Prevent root login |
| 132 | + PermitRootLogin no |
| 133 | + |
| 134 | + # Disable nonpublic key authentication |
| 135 | + KbdInteractiveAuthentication no |
| 136 | + PasswordAuthentication no |
| 137 | + |
| 138 | + # Only allow the admin user to log in |
| 139 | + AllowUsers <username> |
| 140 | + |
| 141 | + # Only allow public key authentication |
| 142 | + AuthenticationMethods publickey |
| 143 | + ``` |
| 144 | + |
| 145 | + **Note:** The main point of this step is to make you think about security |
| 146 | + since all the changes proposed here are, in a sense, optional. Some might |
| 147 | + even be considered bad practice like changing the default SSH port. So, do |
| 148 | + your research and harden SSH in a way that you think is right. |
| 149 | + |
| 150 | +13. (Remote as root) Verify SSH config validity: |
| 151 | + |
| 152 | + ```console |
| 153 | + rcctl configtest sshd |
| 154 | + ``` |
| 155 | + |
| 156 | +14. (Remote as root) Restart SSH daemon: |
| 157 | + |
| 158 | + ```console |
| 159 | + rcctl reload sshd |
| 160 | + ``` |
| 161 | + |
| 162 | +15. (Local) SSH as admin user: |
| 163 | + |
| 164 | + ```console |
| 165 | + ssh -p <port> -i /path/to/private/key <username>@<ip> |
| 166 | + ``` |
| 167 | + |
| 168 | + **Note:** To prevent losing access to your server, only exit your root |
| 169 | + session once you've confirmed that you can successfully connect as the admin |
| 170 | + user and run privileged commands. Also, `-p` can be omitted if you didn't |
| 171 | + change the default port on step 12. |
| 172 | + |
| 173 | + **Tip:** You can add the following to your SSH config so you don't have to |
| 174 | + type so many arguments every time: |
| 175 | + |
| 176 | + ```text |
| 177 | + Host <hostname> |
| 178 | + User <username> |
| 179 | + HostName <ip> |
| 180 | + # `Port` can be omitted if you didn't change the default port on step 12 |
| 181 | + Port <port> |
| 182 | + IdentityFile /path/to/private/key |
| 183 | + ``` |
| 184 | + |
| 185 | + Once done, you can SSH with just: |
| 186 | + |
| 187 | + ```console |
| 188 | + ssh <hostname> |
| 189 | + ``` |
| 190 | + |
| 191 | +16. (Remote as admin user) Configure PF as firewall: |
| 192 | + |
| 193 | + ```console |
| 194 | + doas vi /etc/pf.conf |
| 195 | + ``` |
| 196 | + |
| 197 | + Then, change lines 7 and 8 from: |
| 198 | + |
| 199 | + ```text |
| 200 | + block return # block stateless traffic |
| 201 | + pass # establish keep-state |
| 202 | + ``` |
| 203 | + |
| 204 | + To: |
| 205 | + |
| 206 | + ```text |
| 207 | + # Block all connections by default |
| 208 | + block all |
| 209 | + |
| 210 | + # Allow outbound connections |
| 211 | + pass out all |
| 212 | + |
| 213 | + # Only allow SSH inbound connections |
| 214 | + # `<port>` is either the custom port set on step 12 or the default 22 |
| 215 | + pass in on egress proto tcp to egress port <port> |
| 216 | + ``` |
| 217 | + |
| 218 | + **Note:** Like step 12, the main point of this step is to make you think |
| 219 | + about security since the proposed changes here are not mandatory. So, do |
| 220 | + your research and testing and configure PF in a way that you think is right |
| 221 | + for your use case. |
| 222 | + |
| 223 | +17. (Remote as admin user) Verify PF config validity: |
| 224 | + |
| 225 | + ```console |
| 226 | + doas pfctl -nf /etc/pf.conf |
| 227 | + ``` |
| 228 | + |
| 229 | +18. (Remote as admin user) Apply updated PF config: |
| 230 | + |
| 231 | + ```console |
| 232 | + doas pfctl -f /etc/pf.conf |
| 233 | + ``` |
| 234 | + |
| 235 | +19. (Remote as admin user) Check active PF rules: |
| 236 | + |
| 237 | + ```console |
| 238 | + doas pfctl -sr |
| 239 | + ``` |
| 240 | + |
| 241 | +20. (Local) SSH as admin user again to verify PF allows access: |
| 242 | + |
| 243 | + ```console |
| 244 | + ssh -p <port> -i /path/to/private/key <username>@<ip> |
| 245 | + ``` |
| 246 | + |
| 247 | + **Note:** `-p` can be omitted if you didn't change the default port on |
| 248 | + step 12. |
| 249 | + |
| 250 | + Or, if you've added the server in your SSH config: |
| 251 | + |
| 252 | + ```console |
| 253 | + ssh <hostname> |
| 254 | + ``` |
| 255 | + |
| 256 | + **Note:** To prevent losing access to your server, only exit your original |
| 257 | + admin session once you've confirmed that PF successfully allows you to |
| 258 | + connect. |
| 259 | + |
| 260 | +## References |
| 261 | + |
| 262 | +- <https://blog.cschad.com/posts/guide_to_openbsd_75_installation> |
| 263 | +- <https://blog.cschad.com/posts/openbsd_75_post_installation> |
| 264 | +- <https://www.openbsdhandbook.com> |
| 265 | +- <https://www.openbsd.org/faq> |
| 266 | +- <https://man.openbsd.org/ssh.1> |
| 267 | +- <https://man.openbsd.org/man1/passwd.1> |
| 268 | +- <https://man.openbsd.org/syspatch.8> |
| 269 | +- <https://man.openbsd.org/packages.7> |
| 270 | +- <https://man.openbsd.org/pkg_add.1> |
| 271 | +- <https://man.openbsd.org/vi.1> |
| 272 | +- <https://man.openbsd.org/mg.1> |
| 273 | +- <https://man.openbsd.org/nc.1> |
| 274 | +- <https://man.openbsd.org/ftp.1> |
| 275 | +- <https://openports.pl/path/editors/vim,no_x11> |
| 276 | +- <https://openports.pl/path/editors/nano> |
| 277 | +- <https://openports.pl/path/net/curl> |
| 278 | +- <https://openports.pl/path/net/wget2> |
| 279 | +- <https://man.openbsd.org/doas.conf.5> |
| 280 | +- <https://man.openbsd.org/useradd.8> |
| 281 | +- <https://man.openbsd.org/ssh-keygen.1> |
| 282 | +- <https://man.openbsd.org/sshd_config.5> |
| 283 | +- <https://man.openbsd.org/rcctl.8> |
| 284 | +- <https://man.openbsd.org/rc.d.8> |
| 285 | +- <https://man.openbsd.org/ssh_config.5> |
| 286 | +- <https://man.openbsd.org/pf.conf.5> |
| 287 | +- <https://man.openbsd.org/pfctl.8> |
0 commit comments