This Ansible role helps with the administration of accounts at the German exceptional internet hoster Uberspace. It is not officially maintained by the company. I am only one of their customers. It is acting through the user frontend via HTTPS and content parsing, but since there is no official API, things can break easily as soon as Uberspace changes anything in the frontend, specifically does a frontend relaunch etc.
When using this role, make sure that you understand, respect and cherish the philosophy and share the values of Uberspace. Specifically: Don't abuse the provided privileges and don't overburden the technical infrastructure!
When setting the desired price (see below), please make sure you understand the pricing model, and it's implications: https://manual.uberspace.de/en/billing-general/#price / https://blog.uberspace.de/ein-bekenntnis-zur-freien-preiswahl-und-ein-aber/
By using this role, anybody can set up a desired application in a matter of minutes. But beware, you should be aware of what is happening in the back, since you will be responsible for it and the impact it has on its users. That includes updates, privacy and other security aspects. So read through the tasks/*.yml
files to understand it's magic!
This role is tailored to run from a Linux controller only for Uberspace v7, not v6! It can
- Register new account
- Get and set price and get current balance
- Set web login password
- Deploy SSH login authorized key, generate in advance if necessary
- Delete an account
- Trust SSH host keys via local user
known_hosts
file - Gather facts (for other roles/tasks running afterwards)
- Opened ports
- Registered domains
- Web Backends
- Web Headers
- Tools and their versions
- public/private IPv4/v6 addresses
- Hostname and other common variables (E-Mail etc.)
- MySQL password
- Set basic shell aliases
- Register/open new ports
- Set up web backends
- Set tools versions
- Connect domains to the uberspace
- Set A(AAA) and SRV DNS records at the facultative/complementary separate German Domain/DNS hoster INWX (separate tasks file, use
tasks_from: inwx_domains
on theimport_role:
module)
for now. More features may be added in the future, Merge/Pull Requests are much appreciated!
For the INWX part of the role (setting the DNS records), you need to have the inwx.collection
installed, e.g. by running ansible-galaxy collection install inwx.collection
. Also, you need to already have an account over at INWX and register a domain there, under which the records can be managed. If you don't have one, you can still use the rest of the role.
For some PostgreSQL parts, you need to have ansible-galaxy collection install community.postgresql
.
There are some variables necessary to be set in order for this role to function properly, and some more available to control its behaviour. Also, there are some facts gathered which can be used in tasks/role executions afterwards, e.g. to install/configure applications running on the uberspace. Also, there are a couple of files written and read from by default which are security relevant because they contain credentials. Make sure to only use it on encrypted filesystems and add them to your .gitignore
.
uberspace_loginname
- by default{{ ansible_user }}
from the inventoryuberspace_registeradminnmailaddress
- external admin email address, needs to be provideduberspace_price_goal
- default10.00
€, the current suggested priceuberspace_price_crossfinanced_request
- needs to be set to true, if you want to set a price below 5 € (the current limit for uberspaces cross-financed by other Ubernauts out of solidarity)uberspace_credential_destination
- the location and schema for storage and lookup of passwords and other credentials - by default "credentials/uberspace/{{ uberspace_loginname }}/"uberspace_loginpassword
- by default read fromcredentials/uberspace/{{ uberspace_loginname }}/loginpassword
uberspace_loginkey
- by default read from~/.ssh/id_uberspace_{{ uberspace_loginname }}
uberspace_action_setup
- whether to register a new account, set the password or deploy the login-key - by defaultfalse
uberspace_action_delete
- whether to delete an account - by defaultfalse
uberspace_ports_goal
- list of ports used by running services. Since Uberspace can only open ports on an availability base, users cannot request a specific port to be opened. Rather, the length of this list is compared to the actual open ports and the missing number of ports requested. This variable should afterwards be adjusted manually in the code accordingly.uberspace_domains_goal
- list of domains to be registered to the uberspace viauberspace web domain add
uberspace_tools_goal
- dict of web tools and their versions to configureuberspace_basedomain
- base domain for services, e.g.example.com
uberspace_servicedomain
- subdomain under which services should be available, e.g.foo.bar
would result infoo.bar.example.com
inwx_user
- username at INWXinwx_pw
- password at INWX, by default read fromcredentials/inwx/{{ inwx_user }}-pw
inwx_records_a
- list of domains for A and AAAA recordsinwx_records_srv
- dictionary of domains, services and ports for SRV records. The expected structure is like this (xmpp-client
/xmpp-server
are the service names and need to be adjusted for your case, as you can see, theinwx_records_a
list can be reused):
inwx_records_srv:
xmpp-client:
port: "{{ prosody_port_client }}"
domains: ['']
xmpp-server:
port: "{{ prosody_port_server }}"
domains: "{{ inwx_records_a }}"
The above would result in the following DNS resource records:
_xmpp-client._tcp.{{ uberspace_servicedomain }}.{{ uberspace_basedomain }}. 3600 IN SRV 10 0 {{ prosody_port_client }} {{ uberspace_servicedomain }}.{{ uberspace_basedomain }}.
_xmpp-server._tcp.{{ inwx_records_a[0] }}.{{ uberspace_servicedomain }}.{{ uberspace_basedomain }}. 3600 IN SRV 10 0 {{ prosody_port_client }} {{ uberspace_servicedomain }}.{{ uberspace_basedomain }}.
[… more depending on the contents of inwx_records_a]
e.g.
_xmpp-server._tcp.conference.im.example.com. 3600 IN SRV 10 0 43682 im.example.com.
There are a couple more variables available for fine-grained control, please check defaults/main.yml
and vars/main.yml
.
uberspace_ip_public_v4
,uberspace_ip_public_v6
,uberspace_ip_private_v4
,uberspace_ip_private_v6
- The IPv4 and IPv6 addresses of the uberspace. "Private" are the carrier-grade NAT/unique local ones (100.64.x.y
,fed75::xxx::2
) of the user's virtual network interface, "public" are the host's WAN ones, facing the internet (185.26.156.x
/2a00:d0c0:200:0:48a:86ff:fe54:xxxx
). See also Uberspace manual.uberspace_host
- The fully qualified domain name of the host the uberspace is on, likestardust.uberspace.de
.uberspace_ports
- The ports currently opened in the firewall (usinguberspace port list
on the command line)uberspace_domains
- The domains registered to the uberspace (usinguberspace web domain list
on the command line)
There are a couple of files expected, read and written by this role, all in the directory credentials/
next to the playbook .yml
file.
credentials/uberspace/{{ uberspace_loginname }}/loginpassword
- If you provide an empty file, the password will be randomly generated during account creation.credentials/uberspace/{{ uberspace_loginname }}/session
- Provide an empty file. Will automatically be written to as a cache for the web session ID, will automatically be refreshed when the session expired. Using this ID in the HTTP header, you can log into the Uberspace dashboard.credentials/inwx/{{ inwx_user }}-pw
- Required for DNS operations, place there manually beforehand.
The names, locations or lookup methods (e.g. to switch to Ansible Vault) can be changed by overriding the values of defaults/main.yml
.
Using an inventory account-inventory
like this
[g_uberspace_isabell]
isabell.uber.space
and a playbook example.yml
like this
---
- name: Setup, query and delete again an Uberspace
hosts: g_uberspace_isabell
gather_facts: false
vars:
service_port: 40132
uberspace_basedomain: example.com
uberspace_servicedomain: foo.bar
uberspace_ports_goal: [ "{{ service_port }}" ]
uberspace_domains_goal: [ "{{ uberspace_servicedomain }}.{{ uberspace_basedomain }}" ]
inwx_user: isabell
inwx_records_a: [ "{{ uberspace_servicedomain }}" ]
inwx_records_srv:
service-foo:
port: "{{ service_port }}"
domains: "{{ inwx_records_a }}"
roles:
- role: uberspace_account
uberspace_action_setup: true
tasks:
- name: Setup INWX domains/DNS
import_role:
name: uberspace_account
tasks_from: inwx_domains
- name: Setup application
debug:
msg: Do your things here
- name: Delete uberspace
vars:
uberspace_action_delete: true
include_role:
name: uberspace_account
you can execute ansible-playbook -i account-inventory example.yml
. It will register a new account isabell
, gather and display the facts, setup ports and domains including DNS over at INWX and afterwards delete the account again.
- Automatically accept host key on first SSH connect (TOFU) or even already have the key scraped from the dashboard
- Reset/remove host key on deletion (ssh-keygen -R "xxx.uber.space")
- Use https://docs.ansible.com/ansible/latest/collections/community/general/supervisorctl_module.html