2022-03-18 21:00:08 +00:00
# Development
Hurray 🥳 🎉, you are interested in writing code for ntfy! **That's awesome.** 😎
2021-12-02 04:08:12 +00:00
2022-03-18 21:00:08 +00:00
I tried my very best to write up detailed instructions, but if at any point in time you run into issues, don't
hesitate to **contact me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)** .
2022-03-17 02:33:23 +00:00
2021-12-02 04:08:12 +00:00
## ntfy server
2022-03-17 02:33:23 +00:00
The ntfy server source code is available [on GitHub ](https://github.com/binwiederhier/ntfy ). The codebase for the
server consists of three components:
2022-03-18 21:00:08 +00:00
* **The main server/client** is written in [Go ](https://go.dev/ ) (so you'll need Go). Its main entrypoint is at
2022-03-17 02:33:23 +00:00
[main.go ](https://github.com/binwiederhier/ntfy/blob/main/main.go ), and the meat you're likely interested in is
in [server.go ](https://github.com/binwiederhier/ntfy/blob/main/server/server.go ). Notably, the server uses a
[SQLite ](https://sqlite.org ) library called [go-sqlite3 ](https://github.com/mattn/go-sqlite3 ), which requires
[Cgo ](https://go.dev/blog/cgo ) and `CGO_ENABLED=1` to be set. Otherwise things will not work (see below).
* **The documentation** is generated by [MkDocs ](https://www.mkdocs.org/ ) and [Material for MkDocs ](https://squidfunk.github.io/mkdocs-material/ ),
which is written in [Python ](https://www.python.org/ ). You'll need Python and MkDocs (via `pip` ) only if you want to
build the docs.
2022-03-18 17:53:52 +00:00
* **The web app** is written in [React ](https://reactjs.org/ ), using [MUI ](https://mui.com/ ). It uses [Create React App ](https://create-react-app.dev/ )
to build the production build. If you want to modify the web app, you need [nodejs ](https://nodejs.org/en/ ) (for `npm` )
2022-03-18 21:00:08 +00:00
and install all the 100,000 dependencies (*sigh*).
2022-03-17 02:33:23 +00:00
All of these components are built and then **baked into one binary** .
2022-03-18 17:53:52 +00:00
### Navigating the code
Code:
* [main.go ](https://github.com/binwiederhier/ntfy/blob/main/main.go ) - Main entrypoint into the CLI, for both server and client
* [cmd/ ](https://github.com/binwiederhier/ntfy/tree/main/cmd ) - CLI commands, such as `serve` or `publish`
* [server/ ](https://github.com/binwiederhier/ntfy/tree/main/server ) - The meat of the server logic
* [docs/ ](https://github.com/binwiederhier/ntfy/tree/main/docs ) - The [MkDocs ](https://www.mkdocs.org/ ) documentation, also see `mkdocs.yml`
* [web/ ](https://github.com/binwiederhier/ntfy/tree/main/web ) - The [React ](https://reactjs.org/ ) application, also see `web/package.json`
Build related:
* [Makefile ](https://github.com/binwiederhier/ntfy/blob/main/Makefile ) - Main entrypoint for all things related to building
* [.goreleaser.yml ](https://github.com/binwiederhier/ntfy/blob/main/.goreleaser.yml ) - Describes all build outputs (for [GoReleaser ](https://goreleaser.com/ ))
* [go.mod ](https://github.com/binwiederhier/ntfy/blob/main/go.mod ) - Go modules dependency file
* [mkdocs.yml ](https://github.com/binwiederhier/ntfy/blob/main/mkdocs.yml ) - Config file for the docs (for [MkDocs ](https://www.mkdocs.org/ ))
* [web/package.json ](https://github.com/binwiederhier/ntfy/blob/main/web/package.json ) - Build and dependency file for web app (for npm)
The `web/` and `docs/` folder are the sources for web app and documentation. During the build process,
the generated output is copied to `server/site` (web app and landing page) and `server/docs` (documentation).
### Build requirements
2022-03-17 02:33:23 +00:00
* [Go ](https://go.dev/ ) (required for main server)
* [gcc ](https://gcc.gnu.org/ ) (required main server, for SQLite cgo-based bindings)
* [Make ](https://www.gnu.org/software/make/ ) (required for convenience)
* [libsqlite3/libsqlite3-dev ](https://www.sqlite.org/ ) (required for main server, for SQLite cgo-based bindings)
* [GoReleaser ](https://goreleaser.com/ ) (required for a proper main server build)
* [Python ](https://www.python.org/ ) (for `pip` , only to build the docs)
* [nodejs ](https://nodejs.org/en/ ) (for `npm` , only to build the web app)
2022-03-18 17:53:52 +00:00
### Install dependencies
2022-03-18 21:00:08 +00:00
These steps **assume Ubuntu** . Steps may vary on different Linux distributions.
2022-03-18 17:53:52 +00:00
First, install [Go ](https://go.dev/ ) (see [official instructions ](https://go.dev/doc/install )):
``` shell
2022-03-18 21:00:08 +00:00
wget https://go.dev/dl/go1.18.linux-amd64.tar.gz
2022-03-18 17:53:52 +00:00
rm -rf /usr/local/go & & tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
go version # verifies that it worked
```
Install [GoReleaser ](https://goreleaser.com/ ) (see [official instructions ](https://goreleaser.com/install/ )):
``` shell
go install github.com/goreleaser/goreleaser@latest
goreleaser -v # verifies that it worked
```
Install [nodejs ](https://nodejs.org/en/ ) (see [official instructions ](https://nodejs.org/en/download/package-manager/ )):
``` shell
curl -fsSL https://deb.nodesource.com/setup_17.x | sudo -E bash -
sudo apt-get install -y nodejs
2022-03-18 21:00:08 +00:00
npm -v # verifies that it worked
2022-03-18 17:53:52 +00:00
```
Then install a few other things required:
``` shell
sudo apt install \
build-essential \
libsqlite3-dev \
gcc-arm-linux-gnueabi \
gcc-aarch64-linux-gnu \
python3-pip \
2022-03-18 21:00:08 +00:00
upx \
git
2022-03-18 17:53:52 +00:00
```
### Check out code
Now check out via git from the [GitHub repository ](https://github.com/binwiederhier/ntfy ):
2022-03-17 02:33:23 +00:00
=== "via HTTPS"
2022-03-18 17:53:52 +00:00
``` shell
2022-03-17 02:33:23 +00:00
git clone https://github.com/binwiederhier/ntfy.git
cd ntfy
```
2022-03-18 17:53:52 +00:00
=== "via SSH"
``` shell
git clone git@github.com:binwiederhier/ntfy.git
cd ntfy
```
2022-03-17 02:33:23 +00:00
2022-03-18 17:53:52 +00:00
### Build all the things
Now you can finally build everything. There are tons of `make` targets, so maybe just review what's there first
by typing `make` :
``` shell
$ make
Typical commands (more see below):
make build - Build web app, documentation and server/client (sloowwww)
2022-05-09 23:46:32 +00:00
make cli-linux-amd64 - Build server/client binary (amd64, no web app or docs)
make install-linux-amd64 - Install ntfy binary to /usr/bin/ntfy (amd64)
2022-03-18 17:53:52 +00:00
make web - Build the web app
make docs - Build the documentation
make check - Run all tests, vetting/formatting checks and linters
...
2022-03-17 02:33:23 +00:00
```
2022-03-18 17:53:52 +00:00
2022-05-14 20:56:44 +00:00
If you want to build the **ntfy binary including web app and docs for all supported architectures** (amd64, armv7, and arm64),
2022-03-18 17:53:52 +00:00
you can simply run `make build` :
``` shell
$ make build
...
# This builds web app, docs, and the ntfy binary (for amd64, armv7 and arm64).
2022-03-18 21:18:52 +00:00
# This will be SLOW (5+ minutes on my laptop on the first run). Maybe look at the other make targets?
2022-03-17 02:33:23 +00:00
```
2022-03-18 17:53:52 +00:00
You'll see all the outputs in the `dist/` folder afterwards:
``` bash
$ find dist
dist
dist/metadata.json
dist/ntfy_arm64_linux_arm64
dist/ntfy_arm64_linux_arm64/ntfy
dist/ntfy_armv7_linux_arm_7
dist/ntfy_armv7_linux_arm_7/ntfy
dist/ntfy_amd64_linux_amd64
dist/ntfy_amd64_linux_amd64/ntfy
dist/config.yaml
dist/artifacts.json
```
If you also want to build the **Debian/RPM packages and the Docker images for all supported architectures** , you can
use the `make release-snapshot` target:
``` shell
$ make release-snapshot
...
# This will be REALLY SLOW (sometimes 5+ minutes on my laptop)
```
During development, you may want to be more picky and build only certain things. Here are a few examples.
2022-03-18 21:00:08 +00:00
### Build the ntfy binary
2022-05-09 23:46:32 +00:00
To build only the `ntfy` binary **without the web app or documentation** , use the `make cli-...` targets:
2022-03-18 17:53:52 +00:00
``` shell
2022-03-18 21:00:08 +00:00
$ make
2022-05-21 15:45:11 +00:00
Build server & client (using GoReleaser, not release version):
make cli - Build server & client (all architectures)
make cli-linux-amd64 - Build server & client (Linux, amd64 only)
make cli-linux-armv6 - Build server & client (Linux, armv6 only)
make cli-linux-armv7 - Build server & client (Linux, armv7 only)
make cli-linux-arm64 - Build server & client (Linux, arm64 only)
make cli-windows-amd64 - Build client (Windows, amd64 only)
make cli-darwin-all - Build client (macOS, arm64+amd64 universal binary)
2022-03-18 17:53:52 +00:00
```
2022-05-09 23:46:32 +00:00
So if you're on an amd64/x86_64-based machine, you may just want to run `make cli-linux-amd64` during testing. On a modern
system, this shouldn't take longer than 5-10 seconds. I often combine it with `install-linux-amd64` so I can run the binary
2022-03-18 17:53:52 +00:00
right away:
``` shell
2022-05-09 23:46:32 +00:00
$ make cli-linux-amd64 install-linux-amd64
2022-03-18 17:53:52 +00:00
$ ntfy serve
```
2022-03-18 21:18:52 +00:00
**During development of the main app, you can also just use `go run main.go` **, as long as you run
2022-05-09 23:46:32 +00:00
`make cli-deps-static-sites` at least once and `CGO_ENABLED=1` :
2022-03-18 17:53:52 +00:00
``` shell
2022-03-18 21:18:52 +00:00
$ export CGO_ENABLED=1
2022-05-09 23:46:32 +00:00
$ make cli-deps-static-sites
2022-03-18 17:53:52 +00:00
$ go run main.go serve
2022/03/18 08:43:55 Listening on :2586[http]
2022-03-18 21:18:52 +00:00
...
```
2022-03-18 17:53:52 +00:00
2022-05-09 23:46:32 +00:00
If you don't run `cli-deps-static-sites` , you may see an error *`pattern ...: no matching files found`* :
2022-03-18 17:53:52 +00:00
```
2022-03-18 21:18:52 +00:00
$ go run main.go serve
server/server.go:85:13: pattern docs: no matching files found
```
This is because we use `go:embed` to embed the documentation and web app, so the Go code expects files to be
2022-05-09 23:46:32 +00:00
present at `server/docs` and `server/site` . If they are not, you'll see the above error. The `cli-deps-static-sites`
2022-05-21 15:45:11 +00:00
target creates dummy files that ensure that you'll be able to build.
2022-03-18 21:18:52 +00:00
2022-05-21 15:45:11 +00:00
While not officially supported (or released), you can build and run the server **on macOS** as well. Simply run
`make cli-darwin-server` to build a binary, or `go run main.go serve` (see above) to run it.
2022-03-18 17:53:52 +00:00
2022-03-18 21:00:08 +00:00
### Build the web app
The sources for the web app live in `web/` . As long as you have `npm` installed (see above), building the web app
is really simple. Just type `make web` and you're in business:
2022-03-18 17:53:52 +00:00
2022-03-18 21:00:08 +00:00
``` shell
$ make web
...
2022-03-18 17:53:52 +00:00
```
2022-03-18 21:00:08 +00:00
This will build the web app using Create React App and then **copy the production build to the `server/site` folder** , so
2022-05-09 23:46:32 +00:00
that when you `make cli` (or `make cli-linux-amd64` , ...), you will have the web app included in the `ntfy` binary.
2022-03-17 02:33:23 +00:00
2022-03-18 21:00:08 +00:00
If you're developing on the web app, it's best to just `cd web` and run `npm start` manually. This will open your browser
at `http://127.0.0.1:3000` with the web app, and as you edit the source files, they will be recompiled and the browser
will automatically refresh:
2022-03-17 02:33:23 +00:00
2022-03-18 21:00:08 +00:00
``` shell
$ cd web
$ npm start
```
2022-03-17 02:33:23 +00:00
2022-03-18 21:00:08 +00:00
### Build the docs
The sources for the docs live in `docs/` . Similarly to the web app, you can simply run `make docs` to build the
documentation. As long as you have `mkdocs` installed (see above), this should work fine:
2021-12-02 22:27:31 +00:00
2022-03-18 21:00:08 +00:00
``` shell
$ make docs
...
2021-12-02 22:27:31 +00:00
```
2022-03-18 21:00:08 +00:00
If you are changing the documentation, you should be running `mkdocs serve` directly. This will build the documentation,
serve the files at `http://127.0.0.1:8000/` , and rebuild every time you save the source files:
2021-12-02 22:27:31 +00:00
```
2022-03-18 21:00:08 +00:00
$ mkdocs serve
INFO - Building documentation...
INFO - Cleaning site directory
INFO - Documentation built in 5.53 seconds
INFO - [16:28:14] Serving on http://127.0.0.1:8000/
2021-12-02 22:27:31 +00:00
```
2022-03-18 21:00:08 +00:00
Then you can navigate to http://127.0.0.1:8000/ and whenever you change a markdown file in your text editor it'll automatically update.
2021-12-02 04:08:12 +00:00
## Android app
2021-12-04 01:38:21 +00:00
The ntfy Android app source code is available [on GitHub ](https://github.com/binwiederhier/ntfy-android ).
2021-12-02 22:27:31 +00:00
The Android app has two flavors:
2022-03-18 21:00:08 +00:00
* **Google Play:** The `play` flavor includes [Firebase (FCM) ](https://firebase.google.com/ ) and requires a Firebase account
2021-12-02 22:27:31 +00:00
* **F-Droid:** The `fdroid` flavor does not include Firebase or Google dependencies
2022-03-18 21:00:08 +00:00
### Navigating the code
* [main/ ](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/main ) - Main Android app source code
* [play/ ](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/play ) - Google Play / Firebase specific code
* [fdroid/ ](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/fdroid ) - F-Droid Firebase stubs
* [build.gradle ](https://github.com/binwiederhier/ntfy-android/blob/main/app/build.gradle ) - Main build file
### IDE/Environment
You should download [Android Studio ](https://developer.android.com/studio ) (or [IntelliJ IDEA ](https://www.jetbrains.com/idea/ )
with the relevant Android plugins). Everything else will just be a pain for you. Do yourself a favor. 😀
### Check out the code
2021-12-02 22:27:31 +00:00
First check out the repository:
2022-03-18 21:00:08 +00:00
=== "via HTTPS"
``` shell
git clone https://github.com/binwiederhier/ntfy-android.git
cd ntfy-android
```
=== "via SSH"
``` shell
git clone git@github.com:binwiederhier/ntfy-android.git
cd ntfy-android
```
2021-12-02 22:27:31 +00:00
Then either follow the steps for building with or without Firebase.
2022-03-18 21:00:08 +00:00
### Build F-Droid flavor (no FCM)
!!! info
I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
work without issues. Please give me feedback if it does/doesn't work for you.
2022-05-16 18:53:51 +00:00
Without Firebase, you may want to still change the default `app_base_url` in [values.xml ](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/values.xml )
2021-12-02 22:27:31 +00:00
if you're self-hosting the server. Then run:
```
2022-05-16 18:53:51 +00:00
# Remove Google dependencies (FCM)
sed -i -e '/google-services/d' build.gradle
sed -i -e '/google-services/d' app/build.gradle
2021-12-02 22:27:31 +00:00
# To build an unsigned .apk (app/build/outputs/apk/fdroid/*.apk)
./gradlew assembleFdroidRelease
# To build a bundle .aab (app/fdroid/release/*.aab)
./gradlew bundleFdroidRelease
```
2022-03-18 21:00:08 +00:00
### Build Play flavor (FCM)
!!! info
I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
work without issues. Please give me feedback if it does/doesn't work for you.
2021-12-02 22:27:31 +00:00
To build your own version with Firebase, you must:
2022-03-18 21:00:08 +00:00
2021-12-02 22:27:31 +00:00
* Create a Firebase/FCM account
* Place your account file at `app/google-services.json`
2022-05-16 18:53:51 +00:00
* And change `app_base_url` in [values.xml ](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/values.xml )
2021-12-02 22:27:31 +00:00
* Then run:
```
# To build an unsigned .apk (app/build/outputs/apk/play/*.apk)
./gradlew assemblePlayRelease
# To build a bundle .aab (app/play/release/*.aab)
./gradlew bundlePlayRelease
```
2022-05-26 20:22:47 +00:00
## iOS app
The ntfy iOS app source code is available [on GitHub ](https://github.com/binwiederhier/ntfy-ios ).
!!! info
I haven't had time to move the build instructions here. Please check out the repository instead.