[Blog](https://deploywithox.com/blog) [Guides](https://deploywithox.com/blog#c-guides) # How to self-host diaspora* without Docker on your own VPS Run diaspora* v0.9.1.0 on your own Ubuntu server with ox: a Rails pod with Puma, Sidekiq, Postgres and Redis, from the config that passed its test. Saurav Sharma Oct 17, 2026 10 min read On this page - [What you need](https://deploywithox.com/blog/self-host-diaspora#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-diaspora#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-diaspora#config) - [Postgres, Redis and the worker](https://deploywithox.com/blog/self-host-diaspora#services) - [Updates and backups](https://deploywithox.com/blog/self-host-diaspora#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-diaspora#faq) To self-host diaspora* you need an Ubuntu server, a fork of the diaspora* repo with one `ox.toml` and three small config files added, and 14 variables, six of them required before the first deploy starts. In our run the first deploy took about 12 minutes, and ox set up Postgres and Redis and ran Sidekiq beside the web process. **How we tested** On Oct 17, 2026, ox deployed diaspora* v0.9.1.0 from commit [`150f7788`](https://github.com/diaspora/diaspora/commit/150f7788562e86a26721241e7c23646d9823528d) on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory. The run then redeployed it, backed it up and rebooted the server. Then a separate test agent, one that did not write the config, signed in, shared a public post and saw it at the top of the stream after a reload, and checked the app's services and its backup. To get through, the run's check turned diaspora's sign-up captcha off with SETTINGS_CAPTCHA_ENABLE=false, as config/diaspora.toml.example documents. [diaspora*](https://github.com/diaspora/diaspora) is a social network that you run yourself. Each server is called a pod. People write posts and share them with contacts, sorted into groups called aspects, or with everyone, and pods can exchange posts with one another. The code is under the AGPLv3. It is a Ruby on Rails app served by Puma, with PostgreSQL for its data and Sidekiq for background jobs, which keeps its queues in Redis. ox deployed diaspora* v0.9.1.0 (commit 150f7788) on Oct 17, 2026 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory; the first deploy took 12 minutes and a redeploy took 4 minutes. - **First deploy:** 12 minutes, from adding the project until the app passed the run's first checks. - **Redeploy of the same commit:** 4 minutes, until the app passed the checks again. - **Server:** DigitalOcean, 8 vCPUs and 16 GB of memory (`s-8vcpu-16gb`), with this app alone on it. Every one of the 85 apps we deployed ran on this one size, so it was not picked for this app. - **Memory in use after the reboot:** 1011 MB of 15986 MB, for the whole server: Ubuntu, the app, its services, Caddy and the ox agent. On a server with no apps, ox's tests on real servers hold the agent to 40 MB or less and Caddy to 50 MB or less. - **Services ox runs for it:** `postgres`, `redis`. - **Background processes:** `sidekiq`, each its own systemd unit beside the web process. - **Source:** [github.com/diaspora/diaspora](https://github.com/diaspora/diaspora) at v0.9.1.0, commit [`150f7788`](https://github.com/diaspora/diaspora/commit/150f7788562e86a26721241e7c23646d9823528d). The diaspora* welcome page with its sign-in form ## What you need - An Ubuntu LTS server, of the size in the facts above. The repo pins Ruby 3.3 in `.ruby-version`, and ox installs it. - A GitHub account to fork `diaspora/diaspora`, and an ox account, which you open by signing in with GitHub. - A username, an email address and a password for the first account, the podmin. diaspora* refuses some usernames, `admin` among them, so the run used `podmin`. - A mail server, if you want real email. The run used a test mail catcher. Not tested: real email, federation with other pods, photo uploads, apps that use the diaspora* API, a custom domain and a restore. ## The steps Open the ox dashboard and press Add a server. It shows an install command with a fresh token in it. Run that command on the server as root. This step installs only the ox agent and Caddy. Fork `diaspora/diaspora` on GitHub and take release `v0.9.1.0`, the one the run deployed. Add the `ox.toml` and the three config files shown below, each at its own path, then commit and push. Next write a file named `diaspora.env` on your laptop with a line for each key in the variables list. With the [ox CLI](https://deploywithox.com/docs/cli) signed in, run: Shell ```bash ox new /diaspora ox review diaspora --from-file diaspora.env --wait ``` The review saves your values and starts the first deploy, and `--wait` prints the run until it ends. The browser has the same two steps, as the [quickstart](https://deploywithox.com/docs/quickstart) shows. When the deploy is green, open the https address ox shows, since diaspora* forces https. The welcome page has the sign-in form, and it asks for a username, not an email: type the ones you set in `ADMIN_USERNAME` and `ADMIN_PASSWORD`. On the Stream, click the box that says "Start a conversation...", set the audience to Public and press Share. The post shows at the top of the Stream and stays there after a reload. The preview address was the only one the run used. A domain of your own was not part of it, and the [domains page](https://deploywithox.com/docs/operate/domains) covers how ox adds one. ## The ox.toml, line by line TOML ```toml # diaspora* on ox: a Rails pod (Puma) with Sidekiq, PostgreSQL and Redis, set # up as its installation guide says: config/database.yml and # config/diaspora.toml (committed beside this file), script/configure_bundler, # bin/bundle install, assets:precompile, db:migrate, then script/server's two # processes (the Procfile's web and sidekiq). Settings the operator chooses # are variables: diaspora* reads each setting from the environment, named # after its path (environment.url is ENVIRONMENT_URL). # ENVIRONMENT_URL is the pod's address: every account's handle is # user@, for good, so it is set before the first deploy. # RSA_PRIVATE_KEY signs OpenID Connect ID tokens (config/oidc_key.pem, which # diaspora* would otherwise make anew in each release). The ADMIN_* keys make # the pod's first admin (the podmin) in the migrate step. required_variables = [ "ENVIRONMENT_URL", "SECRET_KEY_BASE", "RSA_PRIVATE_KEY", "ADMIN_USERNAME", "ADMIN_EMAIL", "ADMIN_PASSWORD", ] [app] # The Procfile's web process; config/puma.rb binds server.listen and writes # server.pid in tmp/pids, which ox makes in each release. start = 'RAILS_ENV=production SERVER_LISTEN="tcp://127.0.0.1:$PORT" exec bin/puma -C config/puma.rb' [static] paths = { "/assets" = "public/assets" } [build] install = ''' printf '%s\n' "$RSA_PRIVATE_KEY" > config/oidc_key.pem chmod 600 config/oidc_key.pem RAILS_ENV=production script/configure_bundler bin/bundle install yarn install --frozen-lockfile --production=false ''' commands = [ # Also writes public/404.html, 422.html and 500.html (lib/tasks/assets.rake). "RAILS_ENV=production bin/rake assets:precompile", # AGPL: every page links to /source.tar.gz, the code the pod runs, which # script/server makes from git. "git archive --format=tar.gz -o public/source.tar.gz HEAD", ] # db:migrate, then the podmin: made once from the ADMIN_* variables (a # password changed in the pod later is kept), made an admin on every deploy. migrate = ''' RAILS_ENV=production bin/rake db:migrate RAILS_ENV=production bin/rails runner ' name = ENV.fetch("ADMIN_USERNAME") user = User.find_by(username: name) if user puts "podmin #{name}: exists" else password = ENV.fetch("ADMIN_PASSWORD") user = User.build(username: name, email: ENV.fetch("ADMIN_EMAIL"), language: "en", password: password, password_confirmation: password) user.save! user.seed_aspects puts "podmin #{name}: created" end Role.add_admin(user.person) ' ''' [workers] # The Procfile's sidekiq: federation, mail and the scheduled jobs. sidekiq = "RAILS_ENV=production exec bin/bundle exec sidekiq" [services] postgres = {} redis = {} [storage] # Photos and avatars (CarrierWave), and the pod's log files. keep = ["public/uploads", "log"] ``` - `required_variables` names the pod's address, the session key, the OpenID Connect signing key and the three `ADMIN` keys. A missing one stops the deploy before the long build. - `start` is the Procfile's web line, Puma with diaspora*'s own `config/puma.rb`. diaspora* reads each setting from an environment variable named after its path, so `SERVER_LISTEN` sets `server.listen` to the loopback address and the port ox gives the app. - `[static]` lets Caddy serve `/assets` from `public/assets`. The test agent saw every asset request there answer 200. - `install` writes the RSA key to `config/oidc_key.pem`, since diaspora* otherwise makes a new key for each release. diaspora*'s `script/configure_bundler` installs only the `postgresql` gem group and skips the test and development gems. Then `bin/bundle install` and `yarn install` fetch the packages. - The build `commands` run `assets:precompile`, which builds the scripts and styles, and `git archive` makes `public/source.tar.gz`. The AGPL asks a pod to offer its code, and diaspora* links that file from its pages. Its `script/server` would make it, but this config starts Puma directly. - `migrate` runs `db:migrate`, then a short Rails script makes the podmin from the `ADMIN` variables the first time only, so a password changed later is kept, and makes sure the account is an admin on every deploy. - `sidekiq` in `[workers]` is the Procfile's second line. It delivers posts to other pods, sends mail and processes photos. `[services]` asks for Postgres and Redis, and `[storage]` keeps `public/uploads`, where photos and avatars go, and `log` across deploys. `config/database.yml` Code ``` # diaspora*'s database.yml.example, reduced to the one database ox gives the # pod: Rails reads its address from DATABASE_URL, and script/configure_bundler # reads the adapter here to install the postgresql gem group. production: adapter: postgresql encoding: unicode ``` `config/diaspora.toml` Code ``` # diaspora*'s settings for a pod on ox (config/diaspora.toml.example names # each one). The pod's address and the rest the operator chooses come from # variables: diaspora* reads every setting from the environment too, named # after its path (environment.url is ENVIRONMENT_URL). [configuration.environment] # Ubuntu's CA bundle, as the example says for Debian and Ubuntu. certificate_authorities = "/etc/ssl/certs/ca-certificates.crt" [configuration.environment.assets] # No nginx in front: the pod serves its uploads (public/uploads) itself. serve = true [configuration.server] rails_environment = "production" # diaspora* reads this environment's table before [configuration]; the # example keeps it, empty, and without it every process warns at start. [production] ``` `config/initializers/secret_token.rb` Code ``` # frozen_string_literal: true # diaspora* generates this file with a random key on first start # (lib/tasks/generate_session_secret.rake); on ox the key is the # SECRET_KEY_BASE variable, the same for every release and process. Diaspora::Application.config.secret_key_base = ENV.fetch("SECRET_KEY_BASE") ``` diaspora*'s installation steps ask a podmin to write these, cut down for ox. `config/database.yml` names only the adapter, because Rails reads the address from `DATABASE_URL`. `config/diaspora.toml` points diaspora* at Ubuntu's certificate bundle, makes the pod serve its own uploads, and holds an empty `[production]` table, which diaspora* looks up first and warns about when it is missing. `config/initializers/secret_token.rb` reads the session key from `SECRET_KEY_BASE`. diaspora* otherwise writes that file with a random key in each checkout, so each release would sign cookies differently. Shell ```bash ENVIRONMENT_URL SECRET_KEY_BASE RSA_PRIVATE_KEY ADMIN_USERNAME ADMIN_EMAIL ADMIN_PASSWORD ADMINS_ACCOUNT ADMINS_PODMIN_EMAIL SETTINGS_AUTOFOLLOW_ON_JOIN MAIL_ENABLE MAIL_SENDER_ADDRESS MAIL_SMTP_HOST MAIL_SMTP_PORT MAIL_SMTP_AUTHENTICATION ``` `ENVIRONMENT_URL` is `${PUBLIC_URL}`, a reference ox fills in with the project's address. diaspora*'s example file says never to change it after setup, because the database stores it and every handle is `username@host`. `SECRET_KEY_BASE` is a random string. diaspora*'s own task writes 80 hexadecimal characters, which `openssl rand -hex 40` also makes, and changing it later signs everyone out. `RSA_PRIVATE_KEY` is a PEM private key, such as the output of `openssl genrsa 4096`. It runs over many lines, so put it in double quotes in the `.env` file. `ADMIN_USERNAME`, `ADMIN_EMAIL` and `ADMIN_PASSWORD` are the first account. `ADMINS_ACCOUNT` and `ADMINS_PODMIN_EMAIL` are the pod's contact settings, which the run pointed at that same username and email. New accounts follow the diaspora* HQ account unless `SETTINGS_AUTOFOLLOW_ON_JOIN` is false, and the run set it to false. The `MAIL` keys turn mail on and name the sender, the mail server, its port and the login method. The run used a test catcher, so no real mail went out. See [variables](https://deploywithox.com/docs/operate/variables) for how references work. ## Postgres, Redis and the worker Postgres holds the pod's data and Redis holds Sidekiq's queues. Right after the test agent shared its post, the Sidekiq journal showed the jobs `DeferredDispatch`, `ReceiveLocal` and `PublishToHub` done. The sign-up page asks for a captcha unless `SETTINGS_CAPTCHA_ENABLE` is false, as the box above says. Sign-up through the captcha was not tested. ## Updates and backups To move to a new release, merge its tag into your fork and push, or run `ox deploy diaspora --wait`. ox builds the new release beside the running one, runs the migration and switches once the new one answers. Read `Changelog.md` in the repo first: the 0.9.0.0 entry asks podmins to move to the TOML settings file. Back up now on the Backups tab takes a backup at once, and `ox backups diaspora` lists them. After the run took one, its backup folder held three Postgres dumps (that one and two taken before a migrate) and an archive of the kept `log` folder. A restore was not tested, and no photo was uploaded, so neither was a backup of `public/uploads`. The [backups page](https://deploywithox.com/docs/operate/backups) covers keeping copies in an S3 bucket. ## Frequently asked questions ### Do I need Docker to self-host diaspora*? No. The repo's only Docker files are in a folder named develop, and its README points to the installation guides on the project's wiki. With ox, the app is built from your fork on the server, and Puma and Sidekiq run as system services beside Postgres and Redis. There is no image to pull. ### How do I make the first diaspora* admin? Set ADMIN_USERNAME, ADMIN_EMAIL and ADMIN_PASSWORD before the first deploy. The migrate step makes that account and gives it the admin role. Sign in with the username, because the form does not take the email. Pick a name other than admin, which diaspora* blocks. The run signed in as podmin. ### Which database does diaspora* need? PostgreSQL, plus Redis for Sidekiq. The repo's example database file also has a MySQL section, but the run used Postgres, so MySQL was not tested. ox sets up Postgres on the server and runs Redis as a unit for the project. ### How much memory does self-hosted diaspora* use? On the run's server, the whole machine used the memory the facts show after a reboot. That counts Puma, Sidekiq, Postgres, Redis, Caddy and the ox agent. ox takes any server from 1 GB up, and says so when memory is why the app stopped. ### Can I change my diaspora* address later? The example config says not to change the address after setup, because the database stores it and every handle contains it. Switching from http to https is the one change it allows. The run used ox's preview address, so its handles carry that address. A domain of your own was not tested. New to running apps on your own server? [How ox self-hosts your apps](https://deploywithox.com/self-hosting) shows what ox sets up on your server. On this page - [What you need](https://deploywithox.com/blog/self-host-diaspora#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-diaspora#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-diaspora#config) - [Postgres, Redis and the worker](https://deploywithox.com/blog/self-host-diaspora#services) - [Updates and backups](https://deploywithox.com/blog/self-host-diaspora#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-diaspora#faq) - [Do I need Docker to self-host diaspora*?](https://deploywithox.com/blog/self-host-diaspora#faq-docker) - [How do I make the first diaspora* admin?](https://deploywithox.com/blog/self-host-diaspora#faq-podmin) - [Which database does diaspora* need?](https://deploywithox.com/blog/self-host-diaspora#faq-database) - [How much memory does self-hosted diaspora* use?](https://deploywithox.com/blog/self-host-diaspora#faq-memory) - [Can I change my diaspora* address later?](https://deploywithox.com/blog/self-host-diaspora#faq-address) Written by Saurav Sharma Builds ox. Writes about running apps on servers you own, without Docker and without a platform bill. [Older post How to self-host Dify 1.17.1 on your own VPS, no Docker](https://deploywithox.com/blog/self-host-dify) [Newer post How to self-host CTFd on your own VPS, without Docker](https://deploywithox.com/blog/self-host-ctfd) ## Keep reading - Guides [Self-Hosted Open-Source Apps Deployed with ox: All 85](https://deploywithox.com/blog/self-hosted-open-source-apps-deployed-with-ox) ox deployed 85 open-source apps from pinned commits on fresh servers, with no Docker. The stacks, services, deploy times and a table of every app. Saurav Sharma Oct 17, 2026 16 min read - Guides [How to self-host AFFiNE on your own VPS without Docker](https://deploywithox.com/blog/self-host-affine) Run AFFiNE v0.27.4 on your own Ubuntu server with ox: Postgres with pgvector, Redis, a Rust and Node build, and an admin made from two variables. Saurav Sharma Oct 17, 2026 12 min read - Guides [How to self-host Akaunting on your own VPS without Docker](https://deploywithox.com/blog/self-host-akaunting) Run Akaunting 3.2.4 on your own Ubuntu server with ox: PHP, MariaDB, a scheduler and the first company and admin made on deploy, from the config that ran. Saurav Sharma Oct 17, 2026 10 min read ## Deploy to a server you own ox sets up systemd, Caddy and PostgreSQL on your Ubuntu server and deploys on every push. Free for your first project. [Sign up with GitHub](https://deploywithox.com/login/github) [Read the docs](https://deploywithox.com/docs)