[Blog](https://deploywithox.com/blog) [Guides](https://deploywithox.com/blog#c-guides) # How to self-host Apache Answer on your own Ubuntu VPS Run Apache Answer v2.0.3, an open-source question and answer platform, on your own Ubuntu server with ox and no Docker: Go and Postgres, as it ran. Saurav Sharma Oct 17, 2026 9 min read On this page - [What you need](https://deploywithox.com/blog/self-host-answer#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-answer#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-answer#config) - [Postgres, sign-up and plugins](https://deploywithox.com/blog/self-host-answer#services) - [Updates and backups](https://deploywithox.com/blog/self-host-answer#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-answer#faq) To self-host Apache Answer you need an Ubuntu server, a fork of the Answer repo with one `ox.toml` file added, and 14 variables, several of them references that ox fills in from its Postgres. In our run the first deploy took about 6 minutes, and the first admin account came from the variables, so nobody opened Answer's install page. **How we tested** On Oct 17, 2026, ox deployed Apache Answer v2.0.3 from commit [`6744295f`](https://github.com/apache/answer/commit/6744295fa888e0621fc9f9a8ace04f1a4daf8554) 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, asked a question, posted an answer to it, and saw both after a reload, and checked the app's services and its backup. [Apache Answer](https://github.com/apache/answer) runs a question and answer site: a community forum, a help center or a team's knowledge base. People ask questions, post answers, vote and tag, and admins manage the site from an admin area. The code is under the Apache 2.0 license. Answer is a Go server with a React interface built into the binary, and it stores its data in PostgreSQL, MySQL or SQLite. This setup uses Postgres, and the build adds four plugins from the project's `answer-plugins` repo. ox deployed Apache Answer v2.0.3 (commit 6744295f) on Oct 17, 2026 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory; the first deploy took 6 minutes and a redeploy took 3 minutes. - **First deploy:** 6 minutes, from adding the project until the app passed the run's first checks. - **Redeploy of the same commit:** 3 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:** 785 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`. - **Source:** [github.com/apache/answer](https://github.com/apache/answer) at v2.0.3, commit [`6744295f`](https://github.com/apache/answer/commit/6744295fa888e0621fc9f9a8ace04f1a4daf8554). The Apache Answer home page listing questions, signed out The Apache Answer question list after signing in as the admin, with Review and Admin in the sidebar A new Apache Answer question about backing up the database, with one answer below it ## What you need - An Ubuntu LTS server. The run used the size in the facts above and measured the memory there. You install no Go, Node or pnpm yourself, because ox installs them from the config. - A GitHub account to fork `apache/answer`, and an ox account, which you open by signing in with GitHub. - A name, an email address and a password for the first admin. The run set up no mail server, so email was not tested. ## The steps In the ox dashboard, press Add a server and run the command it prints on your Ubuntu machine with sudo. It puts the ox agent and Caddy on the machine. Fork `apache/answer` on GitHub and check out the tag `v2.0.3`, the release the run deployed. Add the `ox.toml` shown below at the root of the repo, then commit and push. The deploy added no other file. Next write a file named `answer.env` on your laptop with a line for each of the 14 keys in the variables section. With the [ox CLI](https://deploywithox.com/docs/cli) signed in, run: Shell ```bash ox new /answer ox review answer --from-file answer.env --wait ``` The review saves your values and starts the first deploy, and `--wait` prints the run until it ends. In the browser the same two steps are New project and the review screen, which the [quickstart](https://deploywithox.com/docs/quickstart) walks through. When the deploy is green, open the address ox shows for the project. A signed-out visitor can read the questions. Sign in at `/users/login` with `ADMIN_EMAIL` and `ADMIN_PASSWORD`, and Review and Admin appear in the sidebar. To post, press Create in the top bar, type a title, a body of a few words and at least one tag, then press Post your question. Write an answer under it and press Post your answer. The test agent did that, and after a reload the question and its answer were still there. A wrong password at sign-in was refused. The run served Answer on ox's preview address only. 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 # Apache Answer v2.0.3 (Go, a React UI embedded at build time, postgres), # as its Dockerfile builds it: `make clean build` makes the server, then # script/build_plugin.sh runs `./answer build`, which adds the plugins in # script/plugin_list, builds the UI with pnpm and embeds it (the plain # `make build` embeds an empty UI). The data folder (/data in the image) # holds conf/config.yaml, uploads, i18n and the cache. packages = ["make"] [app] start = "SITE_ADDR=127.0.0.1:$PORT exec ./answer run -C data/" health = "/healthz" [build] commands = [ # generate runs swag, wire and mockgen, which it installs with go install "export GOBIN=\"$PWD/.ox/gobin\" PATH=\"$PWD/.ox/gobin:$PATH\" && make clean build", "chmod 755 answer && ANSWER_MODULE=\"$PWD\" CGO_ENABLED=0 bash script/build_plugin.sh", ] # The image's entrypoint runs init, then upgrade. With AUTO_INSTALL set, # init installs from the variables, makes the admin and exits; on a later # deploy it finds the config and the tables and does nothing. When the # auto-install fails, init goes on serving its install page, so `timeout` # turns that into a failed migrate. upgrade exits 0 even when it fails, so # its "upgrade done" line is the check. migrate = """ INSTALL_PORT=0 timeout 300 ./answer init -C data/ out=$(./answer upgrade -C data/) echo "$out" grep -q 'upgrade done' <<<"$out" """ [services] postgres = {} [storage] keep = ["data"] [tools] node = "22" pnpm = "9.7.0" ``` - `packages` asks ox for `make` from Ubuntu. Answer builds its server through its Makefile. - `start` runs `./answer run -C data/`. The `-C` flag names Answer's data folder (config file, uploads, language files, cache). `SITE_ADDR` overrides the listen address in that config (port 80 on every address by default) with the loopback address and ox's `$PORT`, so only Caddy reaches the app. `exec` hands ox's stop signal to Answer itself. - `health` is `/healthz`, which Answer answers with OK. ox switches traffic once it responds. - The two build commands follow Answer's Dockerfile. The first runs `make clean build`. Its generate step installs swag, wire and mockgen with `go install`, so the line points `GOBIN` at a folder under `.ox` and adds it to `PATH`. The server it compiles has an empty web interface. - The second runs `script/build_plugin.sh`. It calls `./answer build` with the four plugins in `script/plugin_list`, builds the interface with pnpm, embeds it, and replaces the first binary. `chmod 755` and `ANSWER_MODULE` come from the Dockerfile, `CGO_ENABLED=0` from the Makefile. - `migrate` stands in for the image's entrypoint. `answer init` installs the site on the first deploy: with `AUTO_INSTALL` set, it connects to Postgres, writes `data/conf/config.yaml`, creates the tables and makes the admin from your variables. Later deploys find both and init does nothing. Then `answer upgrade` applies the database migrations. Its exit code does not say whether the migrations worked, so the config prints its output and searches it for `upgrade done`. - `INSTALL_PORT=0` is there because init starts an install web server after an auto-install, on port 80 unless told otherwise, and port 0 picks a free one. `timeout 300` ends the step after five minutes if the install cannot finish, because init would otherwise keep serving its install page forever. - `[services]` asks ox for a Postgres database and user for this project, and `[storage]` keeps the `data` folder across deploys. - `[tools]` installs Node 22 and pnpm 9.7.0, the pnpm the Dockerfile installs. ox reads Go from `go.mod`, which says 1.25.0. There are no workers or scheduled jobs: the test agent found one unit for the app on the server and no timers. Shell ```bash AUTO_INSTALL DB_TYPE DB_HOST DB_NAME DB_USERNAME DB_PASSWORD LANGUAGE SITE_NAME SITE_URL CONTACT_EMAIL ADMIN_NAME ADMIN_EMAIL ADMIN_PASSWORD EXTERNAL_CONTENT_DISPLAY ``` `AUTO_INSTALL` only has to be non-empty. Answer checks the value's length, so even `false` turns the auto-install on, and its own `.env.example` ships `AUTO_INSTALL=false`. The run set `true`. `DB_TYPE` is `postgres`; the installer also takes `mysql` and `sqlite3`. `DB_HOST`, `DB_NAME`, `DB_USERNAME` and `DB_PASSWORD` are references to the Postgres service: `${postgres.host}:${postgres.port}`, `${postgres.database}`, `${postgres.user}` and `${postgres.password}`. ox fills them in when it writes the env files, so nobody types a database password. [Variables](https://deploywithox.com/docs/operate/variables) explains references. `LANGUAGE` and `SITE_NAME` (up to 30 characters) set the site's language and title. `SITE_URL` is its own address, and the run set it to `${PUBLIC_URL}`. `CONTACT_EMAIL` is the site's contact. `ADMIN_NAME` takes 2 to 30 characters, `ADMIN_EMAIL` is the admin's sign-in, and `ADMIN_PASSWORD` takes 8 to 32. `EXTERNAL_CONTENT_DISPLAY` is `always_display` or `ask_before_display`: media from other sites shows at once, or after a question. ## Postgres, sign-up and plugins Answer gets its own database and user on the server's Postgres, which you can browse in the Services tab or with `ox explore answer postgres`. A fresh Answer lets anyone register at `/users/register` and asks each new user to confirm their email, which needs the SMTP setting described in the FAQ. Registration was not tested. The four plugins in `script/plugin_list` end in `@latest`, so every build fetches their newest releases, not the ones from your first deploy. ## Updates and backups To move to a newer release, merge its tag into your fork and push, or run `ox deploy answer --wait`. ox builds the new release and runs `migrate`, where upgrade applies the new version's database changes. ox dumps Postgres first, and the run's redeploy left that dump. A rollback was not tested. The run's backups held a Postgres dump and an archive of the `data` folder, from Back up now and from the daily schedule. Run `ox backups answer` to list them. A restore was not tested. The [backups page](https://deploywithox.com/docs/operate/backups) covers copies in an S3 bucket, and [self-hosting with ox](https://deploywithox.com/self-hosting) lists more apps. ## Frequently asked questions ### Do I need Docker to self-host Apache Answer? No. Answer's README shows a docker run command first, but the project is a Go server with a React interface built into it. ox follows the Dockerfile's build steps on the server, runs the binary as a system service and sets up Postgres beside it. An update is a push to your fork or one deploy command. ### Which database does Apache Answer use? Answer's installer accepts PostgreSQL, MySQL and SQLite3. This setup uses the Postgres that ox creates for the project, reached through the DB_ variables as references, so you type no database password. ox dumps that database before each migrate and whenever you press Back up now. ### How do I create the first Apache Answer admin account? Set AUTO_INSTALL, ADMIN_NAME, ADMIN_EMAIL and ADMIN_PASSWORD, along with the database and site variables, before the first deploy. The migrate step installs the site and makes that admin, and you sign in at /users/login. The password needs 8 to 32 characters and the name 2 to 30. ### How much memory does Apache Answer use? The whole server used the memory the facts show, measured after the run's reboot. That counts Answer, Postgres, Caddy and the ox agent, not the earlier Go and pnpm build. ox takes any server from 1 GB up and says so when memory is why an app stopped. ### Does Apache Answer send email? Only after you set an SMTP server in its admin settings. Answer reads no environment variable for mail, and by default it asks new users to confirm their email, so sign-ups wait for a message until SMTP is set. The run set no mail server, so email 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-answer#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-answer#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-answer#config) - [Postgres, sign-up and plugins](https://deploywithox.com/blog/self-host-answer#services) - [Updates and backups](https://deploywithox.com/blog/self-host-answer#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-answer#faq) - [Do I need Docker to self-host Apache Answer?](https://deploywithox.com/blog/self-host-answer#faq-docker) - [Which database does Apache Answer use?](https://deploywithox.com/blog/self-host-answer#faq-database) - [How do I create the first Apache Answer admin account?](https://deploywithox.com/blog/self-host-answer#faq-admin) - [How much memory does Apache Answer use?](https://deploywithox.com/blog/self-host-answer#faq-memory) - [Does Apache Answer send email?](https://deploywithox.com/blog/self-host-answer#faq-email) 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 authentik without Docker on your own VPS](https://deploywithox.com/blog/self-host-authentik) [Newer post How to self-host Akaunting on your own VPS without Docker](https://deploywithox.com/blog/self-host-akaunting) ## 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)