3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】HTMLも知らなかった中学生が、Pythonでチャットアプリを作るまでの1年間の失敗と軌跡

Last updated at Posted at 2025-12-14

初めに

「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の存在自体も知らない
気分 とても楽観的

image.png

最初作った時は自分でも驚くほど無知でした。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~?
状態 サンプルレベルのチャットツールがようやく作れるようになる
気分 楽観的

この時からしばらくお世話になるsupabaseFletに出会いました。Fletは自分がやりたいことを簡単にやらせてくれてHTML,CSSの知識がない自分に役に立ちました。supabaseは当時自宅サーバーという概念がなかったためずっとdatabaseにはこれを頼っていました。自分はhtml,cssの知識がなかったためこれに頼っていました。この時はsocketを使って通信しています。結構それっぽくなっていますが実際はエンジニアがwebsocketなどを学ぶ時に作るサンプル品ぐらいのクオリティでありオフラインメッセージング機能、アカウント機能等は備わっていないものです。この当時から色々調べるようにはなりましたがまだまだ発展途上という感じです。

Projectchat

名前 内容
名前 Projectchat or Codse Chat
作成時期 2025/7~?
状態
気分 難しさを実感する

image.png

この辺りから公開できるレベルのものになってきました。なんなら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~?
状態
気分 絶望を体験する

image.png

これが今回公開されているものです。projectchatの欠点をなくすような形で作られました。しかし実際のところはfletで楽をできていたところを自分で書かないといけなくなってエラーが多くなったりコードが見にくくなったりなどさまざまな災難に悩まされました。そしてキツくなった結果projectchatにあったTODOリスト、匿名参加などのさまざまな機能がなくなってしまいました。なんならもう開発が辛くなった結果プライベートへの参加機能を一回削ぎ落とすまでになりました。projectchatより優れているところがないわけではありません。githubへの連携が強くなりgithubのリポジトリにmessageを保存するようにしたりなどシステム面での進化があります。しかしユーザーからしたらprojectchatが一番だと思います。

以下は開発で学んだことをまとめてものです。

HTML,CSS入門してやったこと

ステップ1:初めてのサイト作り

まずは以下のサイトで HTML と CSS の基礎を学びました。

HTMLタグの基本的な書き方や、CSSでレイアウトを整える方法を理解できたところで、
自分なりに以下のようなWebサイトを作成しました。

自作サイト(homepage-cb3.pages.dev)

ステップ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がある)
    画像.png

テーブルの作成

  • name:テーブル名の設定
  • Description:説明を入力
  • Enable Row Level Security(RLS):一般のkeyではデータ追加等をできなくする
  • Enable Realtime:リアルタイムで更新してくれるようになる
  • Columns:列の設定
    画像.png

URLの取得方法

project設定の中のData APIにあります
画像.png

keyの取得方法

project設定の中のAPI Keysにあります
anon pubricと書いてある方はRLSは有効な場合書き込み等ができません。しかしservice_rolesecretではできますなので使い方には注意してください

画像.png

データの挿入

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 のキャッシュを無効化しました。

ずっとコードを変えたはずなのに反映されない場合、キャッシュを削除したら直ったので、今後同じ問題が起きないようにこの設定を入れています。

サーバーに導入するもの

入れておくべきもの
✅ 安全な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代目のデバイスなどを追加していきます。

bb2e90a3-3214-4743-a857-56ad17551a20.png

そしてOSを選択してアプリをダウンロードしていきます。

image.png

そしたら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
にアクセスします。そしたらログイン画面が出てくるためログインします。
そうすると以下のような画面になります。

image.png

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のファイルを選択してアップロードを押します。

image.png

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を押しましょう。

image.png

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

接続できるとしたのような画面が表示されます

image.png

日本語化

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を公開しておきます。これからは計画を立てながら少しずつチャットツールを更新していこうと思います。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?