Skip to content

Mac から Ubuntu イメージを使用したEC2インスタンスに VNC で接続する

はじめに

ある案件で、Ubuntu イメージから立ち上げた EC2 インスタンスに内製化したアプリケーションから Virtual Network Computing (以下: VNC) で接続するタスクを担当することになりました。

そもそもこの件ではじめて VNC に触れるので構築方法を備忘録として残そうと思います。

作成したコードは以下にあります。 https://github.com/kntks/blog-code/tree/main/2023/12/mac-ubuntu-ec2-vnc

環境

MacM1 Ventura 13.2.1
Terraform1.6.5

MacからVNCでEC2インスタンスにVNCで接続する

構成図

blue-print

TerraformでEC2を構築する

Terraform を使って EC2 インスタンスを構築します。使用する AMI は ubuntu-jammy-22.04 です。

describe-images
Terminal window
$ aws ec2 describe-images --owners amazon --query "sort_by(Images, &CreationDate)[-1]" --filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-arm64-server-**"
{
"Architecture": "arm64",
"CreationDate": "2023-11-28T04:27:45.000Z",
"ImageId": "ami-06da40830d5da5c27",
"ImageLocation": "amazon/ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-arm64-server-20231128",
"ImageType": "machine",
"Public": true,
"OwnerId": "099720109477",
"PlatformDetails": "Linux/UNIX",
"UsageOperation": "RunInstances",
"State": "available",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"DeleteOnTermination": true,
"SnapshotId": "snap-0260ba9ceaa918525",
"VolumeSize": 8,
"VolumeType": "gp2",
"Encrypted": false
}
},
{
"DeviceName": "/dev/sdb",
"VirtualName": "ephemeral0"
},
{
"DeviceName": "/dev/sdc",
"VirtualName": "ephemeral1"
}
],
"Description": "Canonical, Ubuntu, 22.04 LTS, arm64 jammy image build on 2023-11-28",
"EnaSupport": true,
"Hypervisor": "xen",
"ImageOwnerAlias": "amazon",
"Name": "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-arm64-server-20231128",
"RootDeviceName": "/dev/sda1",
"RootDeviceType": "ebs",
"SriovNetSupport": "simple",
"VirtualizationType": "hvm",
"DeprecationTime": "2025-11-28T04:27:45.000Z"
}
tls_private_key

まず、EC2インスタンスを作成し、Session Manager でログインできる状態を作成します。

main.tf
main.tf
locals {
name = "ubuntu-ec2"
vpc_cidr = "10.0.0.0/16"
private_vpc_cidr = "10.1.0.0/16"
azs = ["ap-northeast-1a"]
public_subnets = ["10.0.2.0/24"]
}
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.2.0"
name = local.name
cidr = local.vpc_cidr
azs = local.azs
public_subnets = local.public_subnets
enable_dns_hostnames = true
enable_dns_support = true
enable_nat_gateway = false
manage_default_security_group = true
default_security_group_ingress = []
default_security_group_egress = [
{
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = "0.0.0.0/0"
}
]
}
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-**"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
module "ec2_instance" {
source = "terraform-aws-modules/ec2-instance/aws"
version = "~> 5.5"
name = local.name
subnet_id = element(module.vpc.public_subnets, 0)
ami = data.aws_ami.ubuntu.id
instance_type = "t3.medium"
monitoring = false
# Spot request specific attributes
create_spot_instance = true
spot_price = "0.1"
spot_wait_for_fulfillment = true
spot_type = "persistent"
spot_instance_interruption_behavior = "terminate"
vpc_security_group_ids = [module.vpc.default_security_group_id]
associate_public_ip_address = true
create_iam_instance_profile = true
iam_role_description = "IAM role for EC2 instance"
iam_role_policies = {
AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
}
provider.tf
terraform {
required_version = "~> 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.29"
}
}
}
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
Env = "dev"
}
}
}
backend.tf
terraform {
backend "local" {
path = "terraform.tfstate"
}
}

Session Manager から EC2 にログインする

Terminal window
$ aws ssm start-session --target i-05a3432a5d809706a
Terminal window
$ sudo su
$ id
uid=0(root) gid=0(root) groups=0(root)

必要なツールをインストールする

ここからは VNC 接続を実現するためのツールをインストールします。

Terminal window
$ apt update && apt upgrade -y
$ apt install -y ubuntu-desktop tigervnc-standalone-server

VNC サーバを起動する

インストールが完了すると、vncserver コマンドを実行できます。

Terminal window
$ vncserver -list
TigerVNC server sessions:
X DISPLAY # RFB PORT # RFB UNIX PATH PROCESS ID # SERVER

vncserver を起動すると passwordを設定する必要があるので、設定します。
※後ほどこのパスワードは使用するので覚えておいてください

Terminal window
$ vncserver :1
You will require a password to access your desktops.
Password:
Verify:
Would you like to enter a view-only password (y/n)? y
Password:
Verify:
/usr/bin/xauth: file /root/.Xauthority does not exist
New Xtigervnc server 'ip-10-0-2-203.ap-northeast-1.compute.internal:1 (root)' on port 5901 for display :1.
Use xtigervncviewer -SecurityTypes VncAuth -passwd /root/.vnc/passwd :1 to connect to the VNC server.

Waiting for connections... という文字列が出たら Mac から VNC 接続します。

Terminal window
$ aws ssm start-session --target i-05a3432a5d809706a --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"portNumber":["5901"],"localPortNumber":["5901"]}'
Starting session with SessionId: xxxx-0f20c9338b5b797f1
Port 5901 opened for sessionId xxxx-0f20c9338b5b797f1.
Waiting for connections...

VNC 接続する

Mac で Finder のアプリをクリックすると、画面左上のバーに移動という文字列が見えます。 finder-bar

そのあと、サーバへ移動をクリック move-server-button

先ほど、 aws ssm start-session コマンドで Ubuntu の 5901 port をローカルの 5901 ポートにマッピングしました。なので vnc://127.0.0.1:5901 を入力します。 connect-localhost-vnc

VNC サーバを立ち上げる際 vncserver :1 と入力し、パスワードを設定したと思いますが、ここで、そのパスワードを入力します。 input-password

無事に開きました! ubuntu-desktop

おまけ

vncserver-config-defaults

/etc/tigervnc/vncserver-config-defaults の中身を確認してみます。

メモ: manpage にも同じ内容が書いています

$vncUserDir の設定によって $HOME/.vnc ディレクトリにログが集まるようです。

Terminal window
# $vncUserDir contains the filename for the log files directory of Xtigervnc
# (the server) and the viewers that are connected to it.
#
# Default: $vncUserDir = "$ENV{HOME}/.vnc";

確かにディレクトリが存在します。

Terminal window
$ ls -1 ~/.vnc/
ip-10-0-2-203.ap-northeast-1.compute.internal:5901.log
ip-10-0-2-203.ap-northeast-1.compute.internal:5901.pid
passwd

$vncStartup は起動スクリプトに $vncUserDir/Xtigervnc-session, $vncUserDir/xstartup がない場合に使用されるスクリプトを設定するようです。
デフォルトでは、 /etc/X11/Xtigervnc-session が設定されています。

Terminal window
# $vncStartup points to a script that will be started at the very beginning
# when neither $vncUserDir/Xtigervnc-session nor $vncUserDir/xstartup is present.
# If $vncUserDir/Xtigervnc-session is present, it will be used. Otherwise, we try
# $vncUserDir/xstartup. If this is also absent, then we use the script given by
# $vncStartup. If $vncStartup is specified in $vncUserDir/tigervnc.conf, then this
# script is used unconditionally. That is without checking for the presence of
# $vncUserDir/Xtigervnc-session or $vncUserDir/xstartup.
#
# Default: $vncStartup = "/etc/X11/Xtigervnc-session";
/etc/X11/Xtigervnc-session
$ cat /etc/X11/Xtigervnc-session
#! /bin/sh
test x"$SHELL" = x"" && SHELL=/bin/bash
test x"$1" = x"" && set -- default
if test -r /etc/default/keyboard &&
test -x /usr/bin/setxkbmap; then
. /etc/default/keyboard
/usr/bin/setxkbmap \
-model "${XKBMODEL}" \
-layout "${XKBLAYOUT}" \
-variant "${XKBVARIANT}" \
"${XKBOPTIONS}"
fi
tigervncconfig -iconic &
"$SHELL" -l <<EOF
exec /etc/X11/Xsession "$@"
EOF
tigervncserver -kill $DISPLAY
/etc/tigervnc/vncserver-config-defaults
Terminal window
$ cat /etc/tigervnc/vncserver-config-defaults
# /etc/tigervnc/vncserver-config-defaults written by Joachim Falk. This file is
# in the Public Domain.
#
# This is a configuration file for the tigervnc-standalone-server and the
# tigervnc-scraping-server packages.
#
# After this file, $ENV{HOME}/.vnc/tigervnc.conf will be sourced, so values can
# be overwritten on a per-user basis.
#
# Next, command-line options overwrite the settings in both this file as well as
# the user's tigervnc.conf config file.
#
# Finally, /etc/tigervnc/vncserver-config-mandatory is parsed. If this file
# exists and defines options to be passed to Xtigervnc, they will override any
# of the same options defined in a user's tigervnc.conf file as well as options
# given via the command line. The vncserver-config-mandatory file offers a
# mechanism to establish some basic form of system-wide policy.
#
# ******************************************************************************
# * WARNING! There is nothing stopping users from constructing their own start *
# * script that calls Xtigervnc directly to bypass any options defined in *
# * /etc/tigervnc/vncserver-config-mandatory. *
# ******************************************************************************
#
# See the following manpages for more details:
# - tigervnc.conf(5x)
# - tigervncserver(1)
# - tigervncsession(8)
# - Xtigervnc(1)
#
# This file has Perl syntax and is source from the tigervncserver script. Every
# value has suitable defaults, so you probably don't need any modifications.
# If you want to reactivate default values, you have to specify an undef value.
# For example, $fontPath will set to the default value after
#
# $fontPath = "/foo";
# $fontPath = undef;
#
# If you are missing something, please let me know.
# joachim.falk@gmx.de
# System configuration
# --------------------
#
# This section contains entries that should be true for all users.
# $fontPath should be a comma separated list of fonts to be added to the font
# path. If not specified, the default will apply.
# Example:
# $fontPath = "tcp/localhost:7100"; # would force Xtigervnc to use xfs.
# Example:
# $fontPath = "";
# $fontPath .= "/usr/share/fonts/X11/misc,";
# $fontPath .= "/usr/share/fonts/X11/cyrillic,";
# $fontPath .= "/usr/share/fonts/X11/100dpi/:unscaled,";
# $fontPath .= "/usr/share/fonts/X11/75dpi/:unscaled,";
# $fontPath .= "/usr/share/fonts/X11/Type1,";
# $fontPath .= "/usr/share/fonts/X11/100dpi,";
# $fontPath .= "/usr/share/fonts/X11/75dpi,";
#
# Default: $fontPath = undef; # Use Xtigervnc built-in default font path.
# $PAMService is the PAM service used for plain password authentication
# if one of the security types Plain, TLSPlain, and
# X509Plain is used.
#
# Default: $PAMService = "tigervnc"; # if /etc/pam.d/vnc is absent.
# Default: $PAMService = "vnc"; # if /etc/pam.d/vnc is present.
# $sslAutoGenCertCommand is used to auto generate the certificate
# for the X509Cert and X509Key options. The configuration for
# openssl is taken from /etc/tigervnc/openssl.cnf where we substitute
# @HostName@ by the fully qualified domain name of the host.
#
# Example: $sslAutoGenCertCommand =
# "openssl req -newkey rsa:4096 -x509 -days 365 -nodes";
#
# Default: $sslAutoGenCertCommand =
# "openssl req -newkey ec:/etc/tigervnc/openssl-ecparams.pem -x509 -days 2190 -nodes";
# User configuration
# ------------------
#
# This section contains entries that may change from user to user.
# You can overwrite these settings by providing a ~/.vnc/tigervnc.conf
# configuration file.
# $vncUserDir contains the filename for the log files directory of Xtigervnc
# (the server) and the viewers that are connected to it.
#
# Default: $vncUserDir = "$ENV{HOME}/.vnc";
# $vncPasswdFile contains the filename of the password file for Xtigervnc.
# This file is only used for the security types VncAuth,
# TLSVnc, and X509Vnc.
#
# Default: $vncPasswdFile = "$vncUserDir/passwd";
# $vncStartup points to a script that will be started at the very beginning
# when neither $vncUserDir/Xtigervnc-session nor $vncUserDir/xstartup is present.
# If $vncUserDir/Xtigervnc-session is present, it will be used. Otherwise, we try
# $vncUserDir/xstartup. If this is also absent, then we use the script given by
# $vncStartup. If $vncStartup is specified in $vncUserDir/tigervnc.conf, then this
# script is used unconditionally. That is without checking for the presence of
# $vncUserDir/Xtigervnc-session or $vncUserDir/xstartup.
#
# Default: $vncStartup = "/etc/X11/Xtigervnc-session";
# The $session option controls which X session type will be started. This
# should match one of the files in /usr/share/xsessions. For example, if there
# is a file called gnome.desktop, then $session = "gnome" would start this X
# session. The command to start the session is passed to the $vncStartup
# script. If this is not specified, then /etc/X11/Xtigervnc-session will start
# the session specified by /usr/bin/x-session-manager.
#
# Default: $session = undef;
# $xauthorityFile should be the path to the authority file that should be used
# by the Xtigervnc server.
#
# Default: $xauthorityFile = "$ENV{XAUTHORITY}" # if the env var is defined.
# Default: $xauthorityFile = "$ENV{HOME}/.Xauthority"; # otherwise
# $desktopName should be set to the default name of the desktop.
# This can be changed at the command line with -name.
#
# Default: $desktopName = "${HOSTFQDN}:nn ($USER)" # Where nn is the display number.
# $geometry is is only used by the standalone TigerVNC server. It sets the
# framebuffer width & height. A default can be derived if the
# tigervncserver is run in a X session -- either $ENV{DISPLAY} or the
# session given by $getDefaultFrom -- with the -xdisplaydefaults
# option. The geometry can also be changed at the commandline with
# the -geometry option. Otherwise, the fixed default provided below
# will be used.
#
# Default: $geometry = "1920x1200";
# $depth sets the framebuffer color depth. Must be one of 16, 24, or 32.
# $pixelformat sets the default pixelformat.
# A default can be derived if the tigervncserver is run in a
# X session -- either $ENV{DISPLAY} or the session given by
# $getDefaultFrom -- with the -xdisplaydefaults option. The depth
# and pixelformat can also be changed at the commandline with
# the -depth and -pixelformat options. Otherwise, the fixed
# defaults provided below for the two settings will be used.
#
# Example: $depth = "16";
# $pixelformat = "rgb565";
#
# Default: $depth = "24";
# Default: $pixelformat = undef;
# $wmDecoration sets the adjustment of $geometry to accommodate the window decoration
# used by the X11 window manager. This is used to fully display
# the VNC desktop even if the VNC viewer is not in full screen mode.
#
# Default: $wmDecoration = "8x64";
# $getDefaultFrom sets the display for the -xdisplaydefaults option if
# tigervncserver is not called in an X session, i.e.,
# the $ENV{DISPLAY} variable is not set. The -xdisplaydefaults
# option can be used to derive values for the above three
# options, i.e., $geometry to $pixelformat. The $getDefaultFrom
# value will be added to the call of xdpyinfo.
#
# Example: $getDefaultFrom = "-display localhost:0";
#
# Default: $getDefaultFrom = undef;
# $scrapingGeometry is only used by the scraping TigerVNC server. It specifies
# the screen area that will be shown to VNC clients, e.g.,
# 640x480+320+240. The format is <w>x<h>+<xoff>+<yoff>, where
# `+' signs can be replaced with `-' signs to specify offsets
# from the right and/or from the bottom of the screen.
# Offsets are optional, +0+0 is assumed by default (top left
# corner). If the argument is empty, full screen is shown to
# VNC clients (this is the default).
#
# Example: $scrapingGeometry = "640x480+320+240";
#
# Default: $scrapingGeometry = undef;
# $localhost should the TigerVNC server only listen on localhost for
# incoming VNC connections.
#
# Example: $localhost = "yes";
# Example: $localhost = "no";
#
# Default: $localhost = "yes"; # if $SecurityTypes does not contain any TLS*
# # or X509* security types or the $SecurityTypes
# # does contain at least on *None security type.
# Default: $localhost = "no"; # Otherwise
# $SecurityTypes a comma separated list of security types the TigerVNC
# server will offer. Available are None, VncAuth, Plain,
# TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, and X509Plain.
#
# Example: $SecurityTypes = "X509Vnc,X509Plain,TLSVnc,TLSPlain,VncAuth";
#
# Default: $SecurityTypes = "VncAuth" # if localhost is enabled (the default)
# Default: $SecurityTypes = "VncAuth,TLSVnc" # otherwise
# $PlainUsers a comma separated list of users that are authorized to access
# the VNC server if the security types Plain, TLSPlain, or
# X509Plain are used to establish the connection. The password
# for these users are check by the system via the PAM service
# specified via $PAMService option.
#
# Example: $PlainUsers = "user1,user2";
#
# Default: $PlainUsers only contains the user starting the tigervncserver.
# $X509Cert and $X509Key contan the filenames for a certificate and its
# key that is used for the security types X509None, X509Vnc,
# and X509Plain.
#
# Default: $X509Cert is auto generated if absent and stored in
# ~/.vnc/${HOSTFQDN}-SrvCert.pem
# Default: $X509Key is auto generated if absent and stored in
# ~/.vnc/${HOSTFQDN}-SrvKey.pem
#
# If filenames are given for $X509Cert and $X509Key either here or
# on the commandline via -X509Cert and -X509Key options, then
# the auto generation is disabled and the user has to take care
# that usable certificates are present.
1;
/etc/tigervnc/vncserver.users
Terminal window
$ cat /etc/tigervnc/vncserver.users
# TigerVNC User assignment
#
# This file assigns users to specific VNC display numbers.
# The syntax is <display>=<username>. E.g.:
#
# :2=andrew
# :3=lisa

xstartup

xstartup ファイルを作成してみます。

Terminal window
$ touch ~/.vnc/xstartup
$ chmod 755 ~/.vnc/xstartup
$ vim ~/.vnc/xstartup
#!/bin/sh
# Uncomment the following two lines for normal desktop:
# unset SESSION_MANAGER
# exec /etc/X11/xinit/xinitrc
gnome-session
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &
x-window-manager &
Terminal window
$ systemctl start gdm
$ systemctl status gdm
gdm.service - GNOME Display Manager
Loaded: loaded (/lib/systemd/system/gdm.service; static)
Active: active (running) since Sun 2023-12-03 06:52:34 UTC; 2s ago
Process: 32055 ExecStartPre=/usr/share/gdm/generate-config (code=exited, status=0/SUCCESS)
Main PID: 32060 (gdm3)
Tasks: 3 (limit: 4598)
Memory: 1.5M
CPU: 31ms
CGroup: /system.slice/gdm.service
└─32060 /usr/sbin/gdm3
Dec 03 06:52:34 ip-10-0-2-203 systemd[1]: Starting GNOME Display Manager...
Dec 03 06:52:34 ip-10-0-2-203 systemd[1]: Started GNOME Display Manager.

VNC サーバを起動します。

$ vncserver -kill
$ vncserver :1

特別に何かが変わるわけではありませんが、xstartup ファイルを記述することでデスクトップ環境をカスタマイズできるようにしました。

参考