CC=aarch64-linux-gnu-gcc GOARCH=arm64 GOOS=linux CGO_ENABLED=1 go build
Later I rewrote the engine and switched to modernc.org/sqlite, which is a pure Go port of SQLite with no cgo dependency at all. With that library the cross-compilation problem disappears completely — a plain go build with just GOARCH=arm64 GOOS=linux is all you need.
The Orange Pi was chosen because it is a cheap single-board PC on ARM architecture that can run for a long time.
For example here is the status of the systemd unit for blog engine as you already see.
sudo systemctl status blog
● blog.service - My Blog engine written on Go
Loaded: loaded (/etc/systemd/system/blog.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2026-04-11 14:32:03 UTC; 3 weeks 6 days ago
Main PID: 1006 (webserver)
Tasks: 12 (limit: 2069)
CGroup: /system.slice/blog.service
└─1006 /usr/local/bin/webserver
May 08 16:35:25 orangepipc webserver[1006]: 2026/05/08 16:35:25 http: TLS handshake error from 86.105.57.128:53315: tls: unsupported SSLv2 handshake received
May 08 16:36:58 orangepipc webserver[1006]: 2026/05/08 16:36:58 http: TLS handshake error from 3.143.162.210:39060: acme/autocert: missing server name
May 08 16:37:47 orangepipc webserver[1006]: 2026/05/08 16:37:47 http: TLS handshake error from 3.143.162.210:39252: read tcp 192.168.100.100:443->3.143.162.210:39252: i/o timeout
May 08 16:38:06 orangepipc webserver[1006]: 2026/05/08 16:38:06 http: TLS handshake error from 3.143.162.210:49188: acme/autocert: missing server name
May 08 16:38:11 orangepipc webserver[1006]: 2026/05/08 16:38:11 http: TLS handshake error from 77.83.39.232:46238: acme/autocert: missing server name
May 08 16:45:24 orangepipc webserver[1006]: Fri May 8 16:45:24 2026 200 144.76.32.242:36200 GET /robots.txt
May 08 16:45:24 orangepipc webserver[1006]: Fri May 8 16:45:24 2026 302 144.76.32.242:36204 GET /
May 08 16:45:24 orangepipc webserver[1006]: Fri May 8 16:45:24 2026 200 144.76.32.242:36204 GET /page?p=0
May 08 16:45:24 orangepipc webserver[1006]: Fri May 8 16:45:24 2026 302 144.76.32.242:36216 GET /
May 08 16:45:25 orangepipc webserver[1006]: Fri May 8 16:45:25 2026 200 144.76.32.242:36218 GET /page?p=0
I created a separate user in that case here is the systemd unit itself
cat /etc/systemd/system/blog.service
[Unit]
Description=My Blog engine written on Go
After=network.target
[Service]
User=blog
Group=blog
Type=simple
WorkingDirectory=/home/blog
ExecStart=/usr/local/bin/webserver
Restart=on-failure
EnvironmentFile=/home/blog/env/blog.env
[Install]
WantedBy=multi-user.target
Here is the exact file structure on the server
tree /home/blog/
/home/blog/
├── cert
│ ├── acme_account+key
│ ├── srelog.dev
│ └── srelog.dev+rsa
├── conf.d
│ └── conf.json
├── database
│ └── database.sqlite
├── env
│ └── blog.env
├── log
│ └── access.log
├── public
│ ├── assets
│ │ └── avatar.jpg
│ └── css
│ ├── custom.css
│ ├── github-prettify-theme.css
│ ├── normalize.css
│ └── skeleton.css
├── templates
│ ├── about.gohtml
│ ├── courses.gohtml
│ ├── create.gohtml
│ ├── footer.gohtml
│ ├── header.gohtml
│ ├── links.gohtml
│ ├── login.gohtml
│ ├── post.gohtml
│ ├── posts.gohtml
│ ├── seo_header.gohtml
│ └── update.gohtml
└── uploads
the configuration looks like something like this
cat /home/blog/conf.d/conf.json
{
"server" : {
"addr":":8080",
"saddr":":8443"
},
"database" : {
"dbpath":"database/database.sqlite"
},
"log" : {
"log":"log/access.log"
},
"template" : {
"tmpath":"templates/*.gohtml"
},
"cert" : {
"domain":"srelog.dev"
},
"oauth" : {
"githubauthorizeurl":"https://github.com/login/oauth/authorize",
"githubtokenurl":"https://github.com/login/oauth/access_token",
"redirecturl":"",
"clientid":"CLIENT_ID",
"clientsecret":"CLIENT_SECRET"
}
}
The main challenge I had was configuring port forwarding on my home router. If you have a very cheap router, even if it has DNAT rules, it may simply not work. For example, forwarding everything coming in on the public interface to a private static IP within the local network just didn't work, so I decided to go the easy route:
PUBLIC_IP:443 -> PRIVATE_IP:443 and the same for port 80. To do this on Linux you need to set capabilities on your binary, something like this:
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/webserver
Final thoughts it's not the end for sure in the era of the LLM you can easily refactor the application, add new features so maybe I will update the post or will create the new one.Powered by Golang net/http package