初めに
「LINE教えて」「やだ」「Discordは?」「やだ」
そんな友人と連絡を取るためだけに、知識ゼロからチャットツールを作り始めました。
HTMLすら知らなかった私が、WebSocketに悩み、Fletに救われ、最終的に総務省へ電気通信事業届出を提出し、自宅サーバー(Ubuntu)を構築するに至った1年間の記録です。
DevLinkHubの由来とは?
DevLinkHubは開発者向けのチャットツールにすることを夢見ているためDev(開発者)がLink(つながる)Hub(場所)という意味を込めてDevLinkHubという名前にしました。publicでtestという名前で検証を行って結果、同じ名前でサーバーを作ると一緒に会話をすることができます。しかしプライベートとpublicどちらでも関係なく乱入できたり前のメッセージが見れなかったりととても不安定です。温かい目で見ていただけるとありがたいです。
もう少し後でYouTubeにも投稿するつもりなのでぜひ見てみてください
初めての作品
初めての作品の名前はVisual Chatです。
詳細
| 名前 | 内容 |
|---|---|
| 名前 | Visual Chat |
| 作成時期 | 2024/7~? |
| 状態 | HTML,CSS,JavaScriptの存在自体も知らない |
| 気分 | とても楽観的 |
最初作った時は自分でも驚くほど無知でした。Webサイトを主に構築するHTML,CSS,JavaScriptの存在を知ってクライアントからサーバーまでSocket.ioを使って作っていました。先ほども言った通りとても無知だったためチャットツールは通信できればいいものだと思っていました。そのためUIは現在のDevLinkHubと大差ないほどのものですがシステムは本当に終わっていました。アカウント機能だけでなくオフラインメッセージング機能、チャンネル機能、サーバー機能もありません。
当時書いた通信のコードです。
const { addAbortListener } = require('events');
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require('socket.io');
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/Virtualchat.html'); //chat画面
});
var messagequeue = [];
io.on('connection', (socket) => {
console.log('Client connected');
//room,nametagを聞く そしてそれを使ってjoinする
socket.on('post', (message) => {
console.log('Received message: ' + message);
//chatメッセージ取得用
messagequeue.push(message);
io.emit('serverpost',message); //全員に共有
console.log(messagequeue);
});
socket.on('room',(roomdata) =>{
console.log('room data: ' + roomdata);
var room = roomdata;
//roomメッセージ送信用
//socket.join(roomdata);
socket.on('name',(namedata) =>{
console.log('name data: ' + namedata);
io.emit('messagequeuepost',messagequeue);
io.emit('serverpost',namedata + "が参加しました")
//nametagメッセージ送信用
});
});
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
server.listen(3000, () => {
console.log('Server is listening on port 3000');
});
現在と比べてありえないほど短く今考えればありえないとすぐわかるのですが当時は「メッセージが重複する問題を直せば普通に公開できるのか?」と思っていた記憶があります。
成長と気づき
今度はCodse Chatという名前でした。
詳細
| 名前 | 内容 |
|---|---|
| 名前 | Codse Chat |
| 作成時期 | 2024/11~? |
| 状態 | サンプルレベルのチャットツールがようやく作れるようになる |
| 気分 | 楽観的 |
この時からしばらくお世話になるsupabaseとFletに出会いました。Fletは自分がやりたいことを簡単にやらせてくれてHTML,CSSの知識がない自分に役に立ちました。supabaseは当時自宅サーバーという概念がなかったためずっとdatabaseにはこれを頼っていました。自分はhtml,cssの知識がなかったためこれに頼っていました。この時はsocketを使って通信しています。結構それっぽくなっていますが実際はエンジニアがwebsocketなどを学ぶ時に作るサンプル品ぐらいのクオリティでありオフラインメッセージング機能、アカウント機能等は備わっていないものです。この当時から色々調べるようにはなりましたがまだまだ発展途上という感じです。
Projectchat
| 名前 | 内容 |
|---|---|
| 名前 | Projectchat or Codse Chat |
| 作成時期 | 2025/7~? |
| 状態 | |
| 気分 | 難しさを実感する |
この辺りから公開できるレベルのものになってきました。なんならProject chatが自分の最高傑作と言っていいぐらいです。codsechatの時にはなかったオフラインメッセージング、アカウント機能があったりビジネスチャットツールらしいTODOリスト機能、チャンネル機能本来チャットツールを作ろうと思っていた理由である匿名参加機能もついていました。しかしこれにはいくつかの問題がありました。1つ目はUIが非常に醜いことです。これはシステムに大きく力を入れていたためUIがとてもわかりやすく混乱を招きやすい形になってしまっていました。2つ目は将来の拡張性の不安です。初めての作品なのでしばらく維持したいと思っているのですが自分はsupabaseの無料枠を使用していたりするため500MBしか保存できないという致命的な問題を変えていました。この時はある程度知識がついてきていてrender.comを使ってサービスを公開しようとしていたりグローバルipaddresなど現在に少しずつ近づいていっていました。
電気通信事業届出書について
電気通信事業届出書について
クローズドチャットを実装するには電気通信事業を申請しないといけないことを知ったので申請してみました
電気通信事業届出書(様式第8)について
https://www.soumu.go.jp/main_content/000792999.pdf
電気通信事業届出書(様式第8)に書くことは以下のとおりです。
- 郵便番号
- 住所
- 指名
- メールアドレスもしくは電話番号
- 提供区域
- 事業開始予定年月日(提出日よりも後)
意外にも、必要な情報はこれだけです。
ネットワーク構成図(様式第3)について
https://www.soumu.go.jp/main_content/000792386.pdf
名前の通りネットワーク構成図を書く場所です例
提供する電気通信役務に関する書類(様式第4)について
提供するサービスがあっているものに丸をつけていきます。
chatツールの場合
- 31 インターネット関連サービスのみ
に⚪︎クローズドチャットと書きます
DevLinkHub
| 名前 | 内容 |
|---|---|
| 名前 | DevLinkHub |
| 作成時期 | 2025/9~? |
| 状態 | |
| 気分 | 絶望を体験する |
これが今回公開されているものです。projectchatの欠点をなくすような形で作られました。しかし実際のところはfletで楽をできていたところを自分で書かないといけなくなってエラーが多くなったりコードが見にくくなったりなどさまざまな災難に悩まされました。そしてキツくなった結果projectchatにあったTODOリスト、匿名参加などのさまざまな機能がなくなってしまいました。なんならもう開発が辛くなった結果プライベートへの参加機能を一回削ぎ落とすまでになりました。projectchatより優れているところがないわけではありません。githubへの連携が強くなりgithubのリポジトリにmessageを保存するようにしたりなどシステム面での進化があります。しかしユーザーからしたらprojectchatが一番だと思います。
以下は開発で学んだことをまとめてものです。
HTML,CSS入門してやったこと
ステップ1:初めてのサイト作り
まずは以下のサイトで HTML と CSS の基礎を学びました。
HTMLタグの基本的な書き方や、CSSでレイアウトを整える方法を理解できたところで、
自分なりに以下のようなWebサイトを作成しました。
ステップ2:調べるときに使ったサイト
HTMLやCSSの文法を調べるとき、最初のうちは「どう検索すればいいのか」が分からず、
ChatGPTに頼ることが多かったです。
そんな中で出会ったのが、
「本格的に学びたい方向けWeb制作の学習サポート」でした。
個人的な評価
| 項目 | 評価 |
|---|---|
| 調べやすさ | ◎ |
| 見やすさ | ◎ |
| 量 | △ |
なぜこのような評価なのか
例えば、
「メニューボタンの開閉時に「=」から「×」へアニメーションしながら変化させる方法」
といった記事のように、タグ名や専門用語が分からなくても検索しやすい構成になっています。
また、イラスト付きで視覚的に理解できるため、
特にグリッドレイアウトを作成するときなどにとても助かりました。
該当ページはこちら:
グリットレイアウトの解説ページ
メリットとデメリットまとめ
メリット
- 図解と実例が多く、初心者でも理解しやすい
- 難しい用語を知らなくても目的の情報にたどり着ける
- 各章が体系的に整理されていて、学びやすい構成
デメリット
- コンテンツ数がまだ少なく、すべての疑問を網羅しているわけではない
- 特定のテーマに特化しているため、幅広いトピックを学ぶには他のサイトも併用が必要
javascriptでよく使ったコード
ページの読み込み後に JavaScript ファイルを動的に追加する
このコードは、ページの読み込み後に JavaScript ファイルを動的に追加する方法です。
後から要素を追加したり、必要なときだけスクリプトを読み込みたい場合にとても便利です。
ボタンを押して読み込む方法もありますが、この方法なら自動で読み込まれるので手間が省けます。
<script>
const uuid = self.crypto.randomUUID();
script.src = "{{ url_for('static', path='js/test.js')}}?v="+uuid;
script.type = "text/javascript";
target.insertAdjacentElement("afterend")
</script>
コードの解説
UUIDを生成する
const uuid = self.crypto.randomUUID();
jsファイルの場所の指定とエクリ文字列の指定
'static':HTML,CSS,jsのファイルが入っているファイル
v=:エクリ文字列の指定することによってキャッシュを避けることができる
script.src = "{{ url_for('static', path='js/test.js')}}?v="+uuid;
ファイル形式の指定今回はjsのファイルなため"text/javascript"と指定します。
script.type = "text/javascript";
jsファイルを読み込みます今回は"afterend"なのでHTMLが読み込まれた後に実行されます。
target.insertAdjacentElement("afterend")
要素追加
後から要素を付け加える時に使うコードです。
以下のコードはjQueryを使ってbodyにHTMLcodeの要素を追加するコードです。もちろんbody以外にも好きなところに追加することができます。
$("#channel").append(`HTMLのコード`);
websocket
websocketの仕組みが絵でとてもわかりやすくなっておりしかもよく使う接続方法とmessageを受信した時の書き方などをよく忘れてしまうのでこのサイトはとても重宝しています。(大敗の場合node.jsの記事しか出てこない)
const webSocket = new WebSocket('ws://localhost:3000');
webSocket.addEventListener('open', () => {
console.log('接続成功');
webSocket.send('{"message":"send data"}');
});
webSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
alert(data.message);
});
webSocket.addEventListener('error', (event) => {
console.log('error');
});
webSocket.addEventListener('close', (event) => {
console.log('close');
});
pythonでsupabase使ってみた
初期設定
ライブラリーのインストール
pip install supabase
pip install load_dotenv
supabaseのセットアップコード
from supabase import Client, create_client#supabaseを利用するために必要なライブラリー
import os#.envからdataを取り出すために使う
from dotenv import load_dotenv##envファイルのloadのために使う
load_dotenv()#envファイルのload
os.getenv("supabaseurl")#supabaseurlに入ってるdataの取得
key=os.getenv("supabasekey")#supabasekeyに入ってるdataの取得
Supabase: Client = create_client(url,key)
supabaseの登録
サービスの作成
- Name:サービス名の入力
- Type of Organization:組織のタイプを選択
projectの作成
- Organization:組織の選択
- Name:projectnameの入力
- Database Password:databaseのパスワードを設定(一度も使ったことはない)
- Region:地域を選択(Tokyoがある)
テーブルの作成
- name:テーブル名の設定
- Description:説明を入力
- Enable Row Level Security(RLS):一般のkeyではデータ追加等をできなくする
- Enable Realtime:リアルタイムで更新してくれるようになる
- Columns:列の設定
URLの取得方法
keyの取得方法
project設定の中のAPI Keysにあります
anon pubricと書いてある方はRLSは有効な場合書き込み等ができません。しかしservice_rolesecretではできますなので使い方には注意してください
データの挿入
response = (
Client.table(table)#保存するtable名
.insert({column:data})#保存するdataと保存するcolumn(場所)
.execute()
)
データを読み取る
response = (
Client.table(table)#保存するtable名
.select("*")#テーブルの全てdataを選択
.execute()
)
jsondata = json.dumps(response.data,ensure_ascii=False,indent=2)#ensure_ascii=Falseすることにより日本語記号などもそのまま描画する,indent=2人間に読みやすいようにする
response = json.loads(jsondata)#strからjsonに変換
データの削除
response = (
Client.table(table)#保存するtable名
.delete()
.eq(table, value)#削除するものの指定
.execute()
)
Jsonバージョン
response = (
Client.table(table)#保存するtable名
.update({overwrite:data})
.eq(f"{table}->>{table}",former)#削除するものの指定
.execute()
)
supabaseでよく使うif文
Supabaseでは、データの保存や取得時に「対象が見つからなかった場合」に response.data に空のリスト [] が入ることがあります。この性質を利用して、データが存在しない場合に独自のエラー処理や通知を行うことができます。
Supabaseは基本的に構文エラー以外のエラーを返さないため、このようなチェックを入れておくと便利です。
if response.data == []:
# データが存在しない場合の処理
raise ValueError("対象のデータが見つかりませんでした。")
pythonでエラーハントリングしてみた
try,except
一般的な方法でとても便利な方法です。
内容としては、エラーが発生してもコードを終了させずに別の処理を実行できます。
try,except使い方
try:
print(Hello)
except Exception as e:#大抵のエラーを全て認識してくれる
#エラー発生時の処理
print("エラーが発生しました",e)#エラーを表示させる
Hello は未定義なので NameError が発生し、
except Exception as e の後のコードが実行されます。
as e によって、発生したエラー内容を取得できます。
raise
こちらも一般的な方法でとても便利な方法です。
raise はエラーを意図的に発生させるための構文です。
例えば、想定外の値を検知した時に、自分で定義した例外を発生させることができます。
class errorname(Exception):
pass
raise errorname("意図的にエラーを発生させました。")
クラスを定義することで、エラー名を自由に設定できるため、
エラーハンドリングをより柔軟に行うことができます。
errorname: 意図的にエラーを発生させました。
inspect
inspectは実行元の関数を取得したり動的関数を取得したりなどかなり便利な標準ライブラリーです。
inspect は関数・クラス・モジュールなどの「内部情報」を取得できる標準ライブラリです。
実行元の関数を調べたり、ソースコードを取得したりできます。
実行元の関数取得
この機能を使うことによってどこの関数で実行されたかがわかる様になる。
mainのコードから実行してた場合<module>,関数の中で実行していた場合関数名と表示される
import inspect
def main():
caller = inspect.stack()[1]
print(caller.function)
main()
おまけ
inspect.getsource()は動的関数を取得するために使われていて用途はプラグインなどの外部プログラムを動かす時に使われる
# 関数のソースコードを取得
source_code = inspect.getsource(my_function)
print(source_code)
# そのソースコードを動的に実行
exec(source_code)
個人開発で実際に使ったセット
try,except X raise
try,exceptとraiseを組み合わせるとエラーをとても見やすくできます。
そしてtracebackを使用することによって一番重要な詳しいエラー内容を表示してくれる様になります。
import traceback
class errorname(Exception):
pass
try:
print(Hello)
except Exception:#大抵のエラーを全て認識してくれる
#エラー発生時の処理
raise errorname(traceback.format_exc())
errorname: Traceback (most recent call last):
File "ファイルパス", line 7, in <module>
print(Hello)
^^^^^
NameError: name 'Hello' is not defined
まとめ
-
try, except:基本のエラー処理構文 -
raise:意図的なエラー発生やカスタム例外の作成 -
inspect:関数やクラスの情報を動的に取得 -
traceback:詳細なエラー内容を整形して表示
これらを組み合わせることで、開発中のバグ特定が格段に楽になります。
キャッシュ対策
キャッシュを無効化する方法
開発中にコードを更新してもブラウザのキャッシュが原因で反映されないことがあります。
その対策として、拡張機能 ModHeader を使い、localhost のキャッシュを無効化しました。
- Chrome用: ModHeader - Chromeウェブストア
- Firefox用: ModHeader - Firefoxアドオン
ずっとコードを変えたはずなのに反映されない場合、キャッシュを削除したら直ったので、今後同じ問題が起きないようにこの設定を入れています。
サーバーに導入するもの
入れておくべきもの
✅ 安全なSSH接続するためにTailscale
✅ アプリを動かすDocker
✅ インスタントwifiから公開するためにいるCloudflare Tunnel
あったらいいもの
✅ Docker管理をしやすくするPortainer(便利)
✅ 管理しやすくするためのUbuntu Budgie(念のため)
✅ 管理画面を追加するhomepage
安全なSSH接続するためにTailscale
メリットは
✅ 難しいポート開放・ルーター設定が不要
✅ スマホ・PC・サーバーを簡単にVPNでつなげる
✅ GoogleやGitHubアカウントで簡単ログイン
✅ 高速・セキュアな通信(WireGuardベース)
ダウンロードコマンド
curl -fsSL https://tailscale.com/install.sh | sh
Tailscale起動コマンド
sudo tailscale up
これにアクセスして2代目のデバイスなどを追加していきます。
そしてOSを選択してアプリをダウンロードしていきます。
そしたらmacの場合上の方に出てきてるアプリのアイコンからログインしましょう
opensshのダウンロード
sudo apt install -y openssh-server
opensshの状態確認
sudo systemctl status ssh
SSH接続する
ssh username@ipaddres
ファイヤウォール有効化
# 1. UFW(ファイアウォール)をインストール
sudo apt install ufw
# 2. 一旦すべて拒否(SSH締め出し防止のためまだ有効化しない)
sudo ufw default deny incoming
# 3. SSHは許可する(念のため)
sudo ufw allow ssh
# 4. 【重要】Tailscaleインターフェース(tailscale0)からの通信は「信頼」して全許可
sudo ufw allow in on tailscale0
# 5. Cloudflare Tunnelなどが使うHTTP/HTTPSは許可(必要であれば)
sudo ufw allow 80
sudo ufw allow 443
# 6. ファイアウォール有効化
sudo ufw enable
アプリを動かすDocker
Docker関連を入れる
Docker GPGキーを入れる
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Dockerのリポジトリを入れる
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Docker関係のインストールを入れる
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release -y
アップデートする
sudo apt-get update
Dockerをインストール
sudo apt-get install docker-ce docker-ce-cli containerd.io -y
Dockerを管理者に追加
sudo usermod -aG docker $USER
Docker管理アプリのPortainer
ボリュームを作成する
docker volume create portioner_data
Dockerのコンテナを作る
docker run -d -p 8000:8000 -p 9443:9443 --name portioner --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.11.1
https:ipアドレス:9443
にアクセスします。そしたらログイン画面が出てくるためログインします。
そうすると以下のような画面になります。
Dockerを本番環境に移行
まず初めにDockerfileを作成します。自分の場合は以下のようになりました。このファイルについては調べてみましたがうまく理解することができませんでした。
# /workspaces/DevLinkHub/Dockerfile
FROM python:3.12-slim
# 作業ディレクトリ
WORKDIR /app
# 依存関係をコピー
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# アプリケーションをコピー
COPY src/ ./src
# デフォルトコマンド
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8001"]
version: '3.9'
services:
devlinkhub:
build: .
container_name: devlinkhub
restart: always
ports:
- "8001:8001"
env_file:
- .env
volumes:
- /Volumes/共有ファイル/public/DevLinkHub:/app
working_dir: /app # 作業ディレクトリを /app に設定
command: uvicorn src.main:app --host 0.0.0.0 --port 8001
dockerをビルドする(アーキテクチャが同じ場合)
docker build -t コンテナ名:latest .
docker save -o コンテナ名.tar コンテナ名:latest
docker run -d --name コンテナ名 -p ポート番号 コンテナ名
dockerをビルドする(アーキテクチャが違う場合)
(Intel/AMD用)
mkdir -p ~/.docker/cli-plugins
curl -SL https://github.com/docker/buildx/releases/latest/download/buildx-darwin-arm64 -o ~/.docker/cli-plugins/docker-buildx
chmod +x ~/.docker/cli-plugins/docker-buildx
docker buildx version
docker buildx build --platform linux/amd64 -t コンテナ名:amd64 --load .
docker save -o コンテナ名.tar コンテナ名:amd64
docker run -d --name コンテナ名 -p 8080:80 コンテナ名:amd64
その次にhttps//:ipアドレス:9443にアクセスしてimagesを選択してimportを押します。
そうすると以下のような画面が出てくるため.tarのファイルを選択してアップロードを押します。
Cloudflare Tunnelでサービス公開
Cloudflare の GPG キー追加
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
Cloudflareのリポジトリ追加
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
更新
sudo apt update
Cloudflareのインストール
sudo apt install cloudflared
cloudflaredにログインする
cloudflared login
cloudflaredにログインすることによりトンネルを使用できるようになります。
トンネルを作成
(無料枠の場合最大100個作成可能でサブドメインで分ける時のことを考えておくことが大切)
cloudflared tunnel create トンネル名
トンネル一覧を確認
トンネル一覧の自分が決めたトンネル名の隣にあるIDをコピーしましょう
cloudflared tunnel list
トンネルを入れるためのファイル作成
sudo mkdir -p /etc/cloudflared
トンネルの設定をする
sudo vim /etc/cloudflared/config.yml
tunnel: <id>
credentials-file: <id>.json
ingress:
- hostname: 実際にアクセスするアドレス
service: localでアクセスする方
- service: http_status:404
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
管理画面を追加するhomepage
100以上のサービスとの統合と複数言語への翻訳を備えた、モダンで完全に静的、高速、かつ安全な、完全プロキシ化された、高度にカスタマイズ可能なアプリケーションダッシュボードです。YAMLファイルまたはDockerラベルディスカバリを介して簡単に設定できます。
と公式ページには書いてあります。自分がなんでこれを入れようと思ったかと言うと色々入れてきましたが総合的に管理できるページが欲しかったからです。
起動
docker run -p 3000:3000 -e HOMEPAGE_ALLOWED_HOSTS=* -v /path/to/config:/app/config -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/gethomepage/homepage:latest
unattended-upgradesでパッケージ自動アップデート
以下のコマンドを打って毎日パッケージリストをアップデートできるように設定ファイルを書き換えます。保存するにはescを押した後に:wqと打てば保存できます。
ここは実際にやりましたが実際に更新に成功しているかは確認していません。
sudo vim /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1"; # 毎日パッケージリスト更新
APT::Periodic::Unattended-Upgrade "1"; # 毎日自動アップグレード
APT::Periodic::AutocleanInterval "7"; # 古いキャッシュを7日ごとに削除
ファイル編集コマンド
sudo vim /etc/apt/apt.conf.d/50unattended-upgrades
#セキュリティアップデートのみ
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
#不要パッケージの自動削除
Unattended-Upgrade::Remove-Unused-Dependencies "true";
#自動再起動(必要な場合のみ、時間指定は02:00)
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
#ログ出力
Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";
ファイル編集コマンド
sudo vim /etc/apt/apt.conf.d/50unattended-upgrades
/* セキュリティアップデートのみ */
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
/* 不要パッケージの自動削除 */
Unattended-Upgrade::Remove-Unused-Dependencies "true";
/* 自動再起動(必要な場合のみ、時間指定は02:00) */
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
/* ログ出力 */
Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";
自動アップデートの有効化
sudo dpkg-reconfigure --priority=low unattended-upgrades
そしたらこのような画面が出ると思いますがYesを押しましょう。
Ubuntu Budgieのインストール
Ubuntu Budgie はコミュニティによって開発されたディストリビューションであり、Budgie デスクトップ環境を Ubuntu を中心に統合しています。
と公式は言っており一言でこれを表すとシンプルでモダンかつ軽量なデスクトップ環境。という感じです。ubuntu serverなのになぜ今更desktopを入れるんだと思うかもしれませんがubuntu serverはCUIだけで心配なので念のため入れておきました。
今回はserver用で使うので最小限のものしかインストールしない方でやっていきたいと思います。
Ubuntu Budgieのインストール(一般的なやつ)
sudo apt install ubuntu-budgie-desktop -y
推奨されているVNCサーバーをダウンロード
sudo apt install x11vnc
VNCサーバーのパスワードの設定
x11vnc -storepasswd ~/.vnc/vncpasswd
storepasswd: No such file or directoryなどと出た場合は以下のコマンドを実行しましょう
mkdir -p ~/.vnc
起動
sudo x11vnc -display :0 -auth /var/run/lightdm/root/:0 -forever -loop -noxdamage -repeat -rfbauth /home/devlinkhub/.vnc/passwd -rfbport 5900 -shared
自分はmacなためFinderの移動→サーバーに接続で接続します
接続のurlは以下のような形で入力します
vnc://ipaddres:5900
接続できるとしたのような画面が表示されます
日本語化
sudo apt update
sudo apt install -y fcitx5-mozc
sudo apt purge -y ibus ibus-data ibus-gtk ibus-gtk3 ibus-gtk4 ibus-mozc gir1.2-ibus-1.0
sudo apt install language-pack-ja language-pack-gnome-ja fonts-noto-cjk
終わりに 〜自由を求めた代償〜
結論:自由を求めすぎて、サービスの機能が自由の彼方へ飛んでいきました。
初めての個人開発は反省点だらけでしたが、チャットツールを作る過程で得た知識と、設計ミスの教訓はプライスレスです。
供養のために、現在のProjectchatを公開しておきます。これからは計画を立てながら少しずつチャットツールを更新していこうと思います。











