xxx.xxx.com 構築手順まとめ 肝心のソースコードは無し
Ubuntu / Nginx同居 / HTTPS(LE) / ABR(abr-geocoder) + Flask(Gunicorn) / GSI reverse(座標→住所)
1. 目的と提供API
公開ドメイン
xxx.xxx.com
住所→座標
GET /v1/geocode?address=...&provider=abrg|gsi|nominatim座標→住所(逆引き)
GET /v1/reverse?lat=..&lon=..&provider=gsi|nominatimEXIF→住所
POST /v1/exif/reverse(multipart file=@photo.jpg)内部
ABR:
http://127.0.0.1:3000/geocode / Flask: unix:/run/geoapi/geoapi.sock同居nginx環境の最大の罠は server_name重複 と /.well-known がFlaskに流れる こと。 ここを外すと Let’s Encrypt が失敗→レート制限になります。
2. 全体構成
Internet(443) ↓ Nginx (xxx.xxx.com) ↓ proxy_pass unix:/run/geoapi/geoapi.sock Gunicorn + Flask (geoapi.service) ├─ /v1/geocode → ABR(abr-geocoder) http://127.0.0.1:3000/geocode └─ /v1/reverse → GSI reverse API(外部) ABR server (abrg.service) :3000 (localhostのみ)
公開ポート80/443のみ(ABR:3000は外に出さない)
3. 事前準備(DNS / FW)
- DNS:
xxx.xxx.comの Aレコード → サーバIP(AAAA無しでもOK) - FW:80/443 を許可(UFW例)
sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw status
4. Ubuntu 基本セットアップ
sudo apt update sudo apt install -y nginx curl sqlite3 ca-certificates \ python3-venv python3-pip
Node.js 20(ABR用)
curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs node -v npm -v
5. 配置先・ユーザー
sudo adduser --system --group --home /opt/geoapi geoapi
sudo mkdir -p /opt/geoapi/{abrg,flask}
sudo chown -R geoapi:geoapi /opt/geoapi
以降、ABRデータは /opt/geoapi/abrg/data、Flaskは /opt/geoapi/flask を前提。
6. ABR(abr-geocoder)構築
インストール
sudo npm install -g @digital-go-jp/abr-geocoder abrg --help
データ生成(例:東京都 130001)
sudo -u geoapi mkdir -p /opt/geoapi/abrg/data sudo -u geoapi abrg download -c 130001 -d /opt/geoapi/abrg/data
systemd:/etc/systemd/system/abrg.service
[Unit] Description=ABR Geocoder (abrg) REST server After=network.target [Service] User=geoapi Group=geoapi WorkingDirectory=/opt/geoapi ExecStart=/usr/bin/abrg serve start -d /opt/geoapi/abrg/data -p 3000 Restart=always RestartSec=2 [Install] WantedBy=multi-user.target
有効化と疎通
sudo systemctl daemon-reload sudo systemctl enable --now abrg sudo systemctl status abrg --no-pager curl "http://127.0.0.1:3000/geocode?address=東京都千代田区丸の内1-9-1"
7. Flask(Gunicorn)構築
Flaskは「統一API」と「キャッシュ」「provider切替」を担当。ABR/GSIは裏で切替。
アプリ配置
/opt/geoapi/flask/app.pyにFlaskコードを配置- 重要:gunicornでは
__main__が走らないので、DB初期化は import時に必ず実行
必須修正(例:cacheテーブル作成)
# app.py で init_db() 定義の直後にこれを置く init_db() # ← gunicorn起動でも必ず走る(no such table: cache を防ぐ)
venv & 依存
sudo -u geoapi python3 -m venv /opt/geoapi/flask/.venv sudo -u geoapi /opt/geoapi/flask/.venv/bin/pip install -U pip sudo -u geoapi /opt/geoapi/flask/.venv/bin/pip install flask gunicorn requests pillow
systemd:/etc/systemd/system/geoapi.service
[Unit] Description=Geo API (Flask via Gunicorn) After=network.target abrg.service Requires=abrg.service [Service] User=geoapi Group=www-data WorkingDirectory=/opt/geoapi/flask Environment="PYTHONUNBUFFERED=1" # 公開するなら APIキー推奨 # Environment="API_KEY=YOUR_SECRET" ExecStart=/opt/geoapi/flask/.venv/bin/gunicorn \ --workers 2 \ --bind unix:/run/geoapi/geoapi.sock \ --umask 007 \ app:app Restart=always RestartSec=2 RuntimeDirectory=geoapi [Install] WantedBy=multi-user.target
有効化・ソケット確認
sudo systemctl daemon-reload sudo systemctl enable --now geoapi sudo systemctl status geoapi --no-pager ls -l /run/geoapi/geoapi.sock
切り分け(Nginx抜きで叩く)
curl --unix-socket /run/geoapi/geoapi.sock -G "http://localhost/v1/geocode" \ --data-urlencode "address=東京都千代田区丸の内1-9-1" \ --data-urlencode "provider=abrg"
8. Nginx(同居前提の設定)
server_name 重複は禁止(同じドメインが複数ファイルにあると片方 ignored)。
HTTP(80)まず通す:/etc/nginx/sites-available/giocode
server {
listen 80;
listen [::]:80;
server_name xxx.xxx.com;
# ACME は必ず Nginx が返す(Flaskに流すと認証失敗)
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
default_type "text/plain";
try_files $uri =404;
}
location / {
proxy_pass http://unix:/run/geoapi/geoapi.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
有効化
sudo ln -s /etc/nginx/sites-available/giocode /etc/nginx/sites-enabled/giocode sudo nginx -t && sudo systemctl reload nginx
ACME到達テスト(絶対やる)
sudo mkdir -p /var/www/html/.well-known/acme-challenge echo ok | sudo tee /var/www/html/.well-known/acme-challenge/ping.txt >/dev/null curl -i "http://<PUBLIC_IP>/.well-known/acme-challenge/ping.txt" -H "Host: xxx.xxx.com" # 200 OK + ok が返れば合格
server_name重複チェック
sudo nginx -T | grep -n "server_name giocode\.disasterinformation\.jp"
9. HTTPS(Let’s Encrypt / webroot方式推奨)
同居環境は –nginx より –webroot が安全。
staging(予行)
sudo apt install -y certbot sudo certbot certonly --staging --webroot -w /var/www/html -d xxx.xxx.com
本番
sudo certbot certonly --webroot -w /var/www/html -d xxx.xxx.com sudo systemctl restart nginx
証明書確認(staging混入を防ぐ)
sudo openssl x509 -in /etc/letsencrypt/live/xxx.xxx.com/fullchain.pem -noout -issuer echo | openssl s_client -connect xxx.xxx.com:443 \ -servername xxx.xxx.com 2>/dev/null \ | openssl x509 -noout -issuer -subject
HTTPSのNginx完成形(80→443リダイレクト)
server {
listen 80;
listen [::]:80;
server_name xxx.xxx.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
default_type "text/plain";
try_files $uri =404;
}
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name xxx.xxx.com;
ssl_certificate /etc/letsencrypt/live/xxx.xxx.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/xxx.xxx.com/privkey.pem;
client_max_body_size 20m;
location / {
proxy_pass http://unix:/run/geoapi/geoapi.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
反映
sudo nginx -t && sudo systemctl reload nginx
10. 呼び出し方法(クライアント)
Windows PowerShellは curl が別物なので curl.exe を使う。
住所→座標(ABR)
curl.exe -G "https://xxx.xxx.com/v1/geocode" ^ --data-urlencode "address=東京都千代田区丸の内1-9-1" ^ --data-urlencode "provider=abrg"
逆引き(座標→住所)
curl.exe -G "https://xxx.xxx.com/v1/reverse" ^ --data-urlencode "lat=35.681382" ^ --data-urlencode "lon=139.766084"
EXIF→住所(GPSがあるJPEG)
curl.exe -F "file=@photo.jpg" https://xxx.xxx.com/v1/exif/reverse
11. 運用・ログ・復旧コマンド
# 状態 sudo systemctl status abrg geoapi nginx --no-pager # ログ sudo journalctl -u geoapi -n 200 --no-pager -o cat sudo journalctl -u abrg -n 200 --no-pager -o cat # 再起動 sudo systemctl restart abrg sudo systemctl restart geoapi sudo systemctl restart nginx # 更新テスト sudo certbot renew --dry-run
典型トラブル
- LE失敗→レート制限:
/.well-knownがFlaskへ流れてないか(Hostヘッダcurlで200確認) - staging証明書のまま:opensslのissuerに
(STAGING)が出てないか - Flask 500:
sqlite3.OperationalError: no such table: cache→ import時init_db() - ABR接続不可:
curl http://127.0.0.1:3000/geocode?...とsystemctl status abrg - Nginx同居の衝突:
nginx -T | grep server_nameで重複を潰す
12. 別環境へ展開する時のチェックリスト
- DNS Aレコードが新サーバIPを向いている
- Nginxに
server_name xxx.xxx.comが1つだけ - ACMEパスがNginxで200になる(Hostヘッダcurl)
- ABR:3000 が localhost で稼働
- geoapi.sock が作られ、Nginxがアクセスできる権限(Group=www-data / umask 007)
- 証明書は本番(issuerにSTAGINGが出ない)
- 外部curlで /v1/geocode /v1/reverse がJSONを返す
このHTMLは「別環境にコピーして、そのまま手順書」として使う目的で作ってあります。
